lambda_ref_cat/error.rs
1//! Project-wide error type.
2//!
3//! Every fallible operation in `lambda-ref-cat` returns [`Error`]. The
4//! enum covers lexical, syntactic, evaluation, and heap-side failures.
5
6use crate::heap::Address;
7use crate::syntax::{Position, VarName};
8
9/// All errors in lambda-ref-cat.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum Error {
12 /// The lexer encountered a character that does not begin any token.
13 UnexpectedChar {
14 /// Byte offset in the source where the character was found.
15 at: Position,
16 /// The offending character.
17 ch: char,
18 },
19 /// Input ended while the parser still required more tokens.
20 UnexpectedEnd {
21 /// Short description of what was expected.
22 expected: &'static str,
23 },
24 /// The parser found a token that does not satisfy the current production.
25 UnexpectedToken {
26 /// Byte offset where the offending token began.
27 at: Position,
28 /// Short description of what was expected.
29 expected: &'static str,
30 /// Rendering of the token that was actually found.
31 found: String,
32 },
33 /// Evaluation referenced a variable not bound in the current environment.
34 UnboundVariable {
35 /// The unbound name.
36 name: VarName,
37 },
38 /// Evaluation exceeded its step budget.
39 FuelExhausted {
40 /// The configured step limit that was hit.
41 limit: u64,
42 },
43 /// A dereference or assignment targeted an address not present in the heap.
44 DanglingReference {
45 /// The address that could not be resolved.
46 address: Address,
47 },
48 /// Dereference or assignment was attempted on a value that is not a cell
49 /// reference.
50 NotAReference {
51 /// Rendering of the offending non-reference value.
52 found: String,
53 },
54 /// Application was attempted with a non-function value in the function
55 /// position.
56 NotAFunction {
57 /// Rendering of the offending non-function value.
58 found: String,
59 },
60}
61
62impl std::fmt::Display for Error {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 match self {
65 Self::UnexpectedChar { at, ch } => {
66 write!(f, "unexpected character {ch:?} at byte {}", at.value())
67 }
68 Self::UnexpectedEnd { expected } => {
69 write!(f, "unexpected end of input; expected {expected}")
70 }
71 Self::UnexpectedToken {
72 at,
73 expected,
74 found,
75 } => {
76 write!(
77 f,
78 "unexpected token {found:?} at byte {}; expected {expected}",
79 at.value()
80 )
81 }
82 Self::UnboundVariable { name } => {
83 write!(f, "unbound variable {:?}", name.as_str())
84 }
85 Self::FuelExhausted { limit } => {
86 write!(f, "evaluation exceeded step limit of {limit}")
87 }
88 Self::DanglingReference { address } => {
89 write!(f, "dangling reference to address {address}")
90 }
91 Self::NotAReference { found } => {
92 write!(f, "expected a reference, found {found}")
93 }
94 Self::NotAFunction { found } => {
95 write!(f, "expected a function, found {found}")
96 }
97 }
98 }
99}
100
101impl std::error::Error for Error {}