bock_interp/error.rs
1//! Runtime error type for the Bock interpreter.
2
3use thiserror::Error;
4
5use crate::Value;
6
7/// An error that can occur during Bock program evaluation.
8///
9/// Three variants (`Return`, `Break`, `Continue`) are control-flow signals
10/// rather than true errors; they are propagated up through `eval_expr` and
11/// caught at the appropriate statement handler (function body, loop body).
12#[derive(Debug, Error, PartialEq)]
13pub enum RuntimeError {
14 // ── Type errors ───────────────────────────────────────────────────────
15 #[error("type error: {0}")]
16 TypeError(String),
17
18 // ── Variable / name errors ────────────────────────────────────────────
19 #[error("undefined variable: {name}")]
20 UndefinedVariable { name: String },
21
22 // ── Arithmetic errors ─────────────────────────────────────────────────
23 #[error("division by zero")]
24 DivisionByZero,
25
26 #[error("integer overflow")]
27 IntOverflow,
28
29 // ── Collection errors ─────────────────────────────────────────────────
30 #[error("index out of bounds: index {index} for length {len}")]
31 IndexOutOfBounds { index: i64, len: usize },
32
33 #[error("field not found: {field} on {type_name}")]
34 FieldNotFound { field: String, type_name: String },
35
36 // ── Call errors ───────────────────────────────────────────────────────
37 #[error("not callable: {value}")]
38 NotCallable { value: String },
39
40 #[error("arity mismatch: expected {expected} args, got {got}")]
41 ArityMismatch { expected: usize, got: usize },
42
43 // ── Error propagation (`?`) ───────────────────────────────────────────
44 /// Raised when `?` is applied to `None` or `Err(e)`. Caught by the
45 /// enclosing function body to propagate the error outward.
46 #[error("propagated error: {0}")]
47 Propagated(Box<Value>),
48
49 // ── Literal parse errors ──────────────────────────────────────────────
50 #[error("integer literal parse failed: {0}")]
51 IntParseFailed(String),
52
53 #[error("float literal parse failed: {0}")]
54 FloatParseFailed(String),
55
56 // ── Control-flow signals ──────────────────────────────────────────────
57 /// Carries the return value from a `return` expression.
58 #[error("return")]
59 Return(Box<Value>),
60
61 /// Carries an optional `break` value from a `break` expression.
62 #[error("break")]
63 Break(Option<Box<Value>>),
64
65 /// Signals `continue` inside a loop.
66 #[error("continue")]
67 Continue,
68
69 // ── Misc ──────────────────────────────────────────────────────────────
70 #[error("unreachable code reached")]
71 Unreachable,
72
73 #[error("match failed: no arm matched the scrutinee")]
74 MatchFailed,
75
76 #[error("no handler for effect `{effect}`: provide a handler via a `handling` block, module-level `handle`, or project config")]
77 NoEffectHandler { effect: String },
78
79 #[error("not implemented: {0}")]
80 NotImplemented(String),
81
82 // ── Test assertion errors ─────────────────────────────────────────────
83 /// Raised when a test assertion (e.g., `expect(x).to_equal(y)`) fails.
84 #[error("assertion failed: {0}")]
85 AssertionFailed(String),
86}