1#![forbid(unsafe_code)]
2
3use std::path::PathBuf;
4
5use maat_span::Span;
6
7pub type Result<T> = std::result::Result<T, Error>;
8
9#[derive(Debug, thiserror::Error)]
10pub enum Error {
11 #[error(transparent)]
12 Parse(#[from] ParseError),
13
14 #[error("eval error: {0}")]
15 Eval(#[from] EvalError),
16
17 #[error("compile error: {0}")]
18 Compile(#[from] CompileError),
19
20 #[error("type error: {0}")]
21 Type(#[from] TypeError),
22
23 #[error("vm error: {0}")]
24 Vm(#[from] VmError),
25
26 #[error("decode error: {0}")]
27 Decode(#[from] DecodeError),
28
29 #[error("serialization error: {0}")]
30 Serialization(#[from] SerializationError),
31
32 #[error("module error: {0}")]
33 Module(#[from] ModuleError),
34}
35
36#[derive(Debug, thiserror::Error)]
37#[error("parse error at {}..{}: {message}", span.start, span.end)]
38pub struct ParseError {
39 pub message: String,
40 pub span: Span,
41}
42
43impl ParseError {
44 pub fn new(message: impl Into<String>, span: Span) -> Self {
45 Self {
46 message: message.into(),
47 span,
48 }
49 }
50}
51
52#[derive(Debug, thiserror::Error)]
53pub enum EvalError {
54 #[error("{0}")]
55 Ident(String),
56
57 #[error("{0}")]
58 IndexExpr(String),
59
60 #[error("{0}")]
61 PrefixExpr(String),
62
63 #[error("{0}")]
64 InfixExpr(String),
65
66 #[error("{0}")]
67 Boolean(String),
68
69 #[error("{0}")]
70 Number(String),
71
72 #[error("{0}")]
73 NotAFunction(String),
74
75 #[error("unusable as hash key: {0}")]
76 NotHashable(String),
77
78 #[error("{0}")]
79 Builtin(String),
80}
81
82#[derive(Debug, thiserror::Error)]
86#[error("{kind}")]
87pub struct TypeError {
88 pub kind: TypeErrorKind,
89 pub span: Span,
90}
91
92#[derive(Debug, thiserror::Error)]
94pub enum TypeErrorKind {
95 #[error("type mismatch: expected `{expected}`, found `{found}`")]
96 Mismatch { expected: String, found: String },
97
98 #[error(
99 "type mismatch: expected `{expected}`, found `{found}`\n help: consider using `as {expected}` for explicit numeric conversion"
100 )]
101 NumericMismatch { expected: String, found: String },
102
103 #[error("infinite type: `{0}` occurs in its own definition")]
104 OccursCheck(String),
105
106 #[error("wrong number of arguments: expected {expected}, found {found}")]
107 WrongArity { expected: usize, found: usize },
108
109 #[error("expression of type `{0}` is not callable")]
110 NotCallable(String),
111
112 #[error("numeric overflow: `{value}` out of range for `{target}`")]
113 NumericOverflow { value: String, target: String },
114
115 #[error("division by zero: `{value}`")]
116 DivisionByZero { value: String },
117
118 #[error("unknown type `{0}`")]
119 UnknownType(String),
120
121 #[error("no field `{field}` on type `{ty}`")]
122 UnknownField { ty: String, field: String },
123
124 #[error("no method `{method}` found for type `{ty}`")]
125 UnknownMethod { ty: String, method: String },
126
127 #[error("duplicate type definition `{0}`")]
128 DuplicateType(String),
129
130 #[error("{0}")]
131 MissingTraitMethod(Box<MissingTraitMethodError>),
132
133 #[error("{0}")]
134 TraitMethodSignatureMismatch(Box<TraitMethodSignatureMismatchError>),
135
136 #[error("non-exhaustive patterns in `match`: {missing}")]
137 NonExhaustiveMatch { missing: String },
138
139 #[error("unknown trait `{0}`")]
140 UnknownTrait(String),
141
142 #[error("unsupported: {0}")]
143 Unsupported(String),
144
145 #[error("item `{item}` is private to module `{module}`")]
146 PrivateAccess { item: String, module: String },
147}
148
149#[derive(Debug, thiserror::Error)]
151#[error("missing trait method `{method}` in impl of `{trait_name}` for `{self_type}`")]
152pub struct MissingTraitMethodError {
153 pub trait_name: String,
154 pub self_type: String,
155 pub method: String,
156}
157
158#[derive(Debug, thiserror::Error)]
160#[error(
161 "method `{method}` has wrong signature in impl of `{trait_name}` for `{self_type}`: expected `{expected}`, found `{found}`"
162)]
163pub struct TraitMethodSignatureMismatchError {
164 pub trait_name: String,
165 pub self_type: String,
166 pub method: String,
167 pub expected: String,
168 pub found: String,
169}
170
171impl TypeErrorKind {
172 pub fn at(self, span: Span) -> TypeError {
174 TypeError { kind: self, span }
175 }
176}
177
178#[derive(Debug, thiserror::Error)]
182#[error("{kind}")]
183pub struct CompileError {
184 pub kind: CompileErrorKind,
185 pub span: Option<Span>,
186}
187
188impl CompileError {
189 pub fn new(kind: CompileErrorKind) -> Self {
191 Self { kind, span: None }
192 }
193}
194
195#[derive(Debug, thiserror::Error)]
197pub enum CompileErrorKind {
198 #[error(
199 "constant pool overflow: exceeded maximum of {max} constants (attempted index: {attempted})"
200 )]
201 ConstantPoolOverflow { max: usize, attempted: usize },
202
203 #[error("unsupported operator '{operator}' in {context}")]
204 UnsupportedOperator { operator: String, context: String },
205
206 #[error("unsupported expression type '{expr_type}'")]
207 UnsupportedExpr { expr_type: String },
208
209 #[error("invalid opcode 0x{opcode:02x} at instruction position {position}")]
210 InvalidOpcode { opcode: u8, position: usize },
211
212 #[error("undefined variable '{name}'")]
213 UndefinedVariable { name: String },
214
215 #[error(
216 "symbols table overflow: exceeded maximum of {max} global bindings (attempted to define '{name}')"
217 )]
218 SymbolsTableOverflow { max: usize, name: String },
219
220 #[error(
221 "local variable overflow: exceeded maximum of {max} local bindings in function scope (attempted to define '{name}')"
222 )]
223 LocalsOverflow { max: usize, name: String },
224
225 #[error("scope stack underflow: attempted to leave scope with no enclosing scope")]
226 ScopeUnderflow,
227
228 #[error("`break` outside of a loop")]
229 BreakOutsideLoop,
230
231 #[error("`continue` outside of a loop")]
232 ContinueOutsideLoop,
233
234 #[error("undeclared label `'{label}`")]
235 UndeclaredLabel { label: String },
236
237 #[error("cannot re-assign to immutable variable `{name}`")]
238 ImmutableAssignment { name: String },
239
240 #[error("unknown builtin macro `{name}!`")]
241 UnknownMacro { name: String },
242
243 #[error(
244 "format string has {placeholders} placeholder(s) but {arguments} argument(s) were supplied"
245 )]
246 FormatArgCountMismatch {
247 placeholders: usize,
248 arguments: usize,
249 },
250
251 #[error("`{macro_name}!` requires a format string literal as its first argument")]
252 MacroExpectsFormatString { macro_name: String },
253
254 #[error(
255 "enum `{name}` has {count} variants, exceeding the maximum of {max} (variant tags must fit in 8 bits)"
256 )]
257 VariantTagOverflow {
258 name: String,
259 count: usize,
260 max: usize,
261 },
262}
263
264impl CompileErrorKind {
265 pub fn at(self, span: Span) -> CompileError {
267 CompileError {
268 kind: self,
269 span: Some(span),
270 }
271 }
272}
273
274impl From<CompileErrorKind> for CompileError {
275 fn from(kind: CompileErrorKind) -> Self {
276 Self { kind, span: None }
277 }
278}
279
280#[derive(Debug, thiserror::Error)]
282#[error("{message}")]
283pub struct VmError {
284 pub message: String,
285 pub span: Option<Span>,
286}
287
288impl VmError {
289 pub fn new(message: impl Into<String>) -> Self {
290 Self {
291 message: message.into(),
292 span: None,
293 }
294 }
295
296 pub fn with_span(message: impl Into<String>, span: Span) -> Self {
298 Self {
299 message: message.into(),
300 span: Some(span),
301 }
302 }
303}
304
305impl From<String> for VmError {
306 fn from(message: String) -> Self {
307 Self {
308 message,
309 span: None,
310 }
311 }
312}
313
314impl From<&str> for VmError {
315 fn from(message: &str) -> Self {
316 Self {
317 message: message.to_string(),
318 span: None,
319 }
320 }
321}
322
323#[derive(Debug, thiserror::Error)]
324pub enum DecodeError {
325 #[error(
326 "bytecode truncated: needed {needed} bytes at offset {offset}, but only {available} bytes available"
327 )]
328 UnexpectedEndOfBytecode {
329 offset: usize,
330 needed: usize,
331 available: usize,
332 },
333
334 #[error("unsupported operand width: {0} (valid widths: 1, 2, 4, 8)")]
335 UnsupportedOperandWidth(usize),
336
337 #[error("invalid opcode: 0x{0:02x}")]
338 InvalidOpcode(u8),
339}
340
341#[derive(Debug, thiserror::Error)]
348pub enum SerializationError {
349 #[error("invalid magic bytes: expected MAAT header")]
351 InvalidMagic,
352
353 #[error("unsupported bytecode format version: {0}")]
355 UnsupportedVersion(u32),
356
357 #[error("unexpected end of bytecode at offset {offset}: needed {needed} more bytes")]
359 UnexpectedEof { offset: usize, needed: usize },
360
361 #[error("bytecode encode error: {0}")]
363 PostcardEncode(String),
364
365 #[error("bytecode decode error: {0}")]
367 PostcardDecode(String),
368
369 #[error("bytecode payload too large: {size} bytes exceeds {limit} byte limit")]
371 PayloadTooLarge { size: usize, limit: usize },
372
373 #[error("{field} too large: {size} exceeds limit of {limit}")]
375 ResourceLimitExceeded {
376 field: &'static str,
377 size: usize,
378 limit: usize,
379 },
380}
381
382#[derive(Debug, thiserror::Error)]
387#[error("{file}: {kind}", file = file.display())]
388pub struct ModuleError {
389 pub kind: ModuleErrorKind,
390 pub span: Span,
391 pub file: PathBuf,
393}
394
395#[derive(Debug, thiserror::Error)]
397pub enum ModuleErrorKind {
398 #[error("module `{module_name}` not found; searched: {}", candidates.iter().map(|p| p.display().to_string()).collect::<Vec<_>>().join(", "))]
400 FileNotFound {
401 module_name: String,
402 candidates: Vec<PathBuf>,
403 },
404
405 #[error("cyclic module dependency: {}", cycle.join(" -> "))]
407 CyclicDependency {
408 cycle: Vec<String>,
410 },
411
412 #[error("duplicate module declaration `{module_name}`")]
414 DuplicateModule { module_name: String },
415
416 #[error("parse errors in `{}`:{}", file.display(), messages.iter().map(|m| format!("\n {m}")).collect::<String>())]
418 ParseErrors {
419 file: PathBuf,
420 messages: Vec<String>,
421 },
422
423 #[error("type errors in `{}`:{}", file.display(), messages.iter().map(|m| format!("\n {m}")).collect::<String>())]
425 TypeErrors {
426 file: PathBuf,
427 messages: Vec<String>,
428 },
429
430 #[error("compile errors in `{}`:{}", file.display(), messages.iter().map(|m| format!("\n {m}")).collect::<String>())]
432 CompileErrors {
433 file: PathBuf,
434 messages: Vec<String>,
435 },
436
437 #[error("cannot read `{}`: {message}", path.display())]
439 Io { path: PathBuf, message: String },
440}
441
442impl ModuleErrorKind {
443 pub fn at(self, span: Span, file: PathBuf) -> ModuleError {
446 ModuleError {
447 kind: self,
448 span,
449 file,
450 }
451 }
452}