1use crate::value::ThunkId;
2use tidepool_repr::{JoinId, PrimOpKind, VarId};
3
4#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum ValueKind {
7 Literal(&'static str), Constructor,
9 Closure,
10 Thunk,
11 Other(String),
13}
14
15impl std::fmt::Display for ValueKind {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 match self {
18 ValueKind::Literal(name) => write!(f, "{}", name),
19 ValueKind::Constructor => write!(f, "constructor"),
20 ValueKind::Closure => write!(f, "closure"),
21 ValueKind::Thunk => write!(f, "thunk"),
22 ValueKind::Other(s) => write!(f, "{}", s),
23 }
24 }
25}
26
27#[derive(Debug, Clone)]
29pub enum EvalError {
30 UnboundVar(VarId),
32 ArityMismatch {
34 context: &'static str, expected: usize,
36 got: usize,
37 },
38 TypeMismatch {
40 expected: &'static str,
41 got: ValueKind,
42 },
43 NoMatchingAlt,
45 InfiniteLoop(ThunkId),
47 UnsupportedPrimOp(PrimOpKind),
49 HeapExhausted,
51 NotAFunction,
53 UnboundJoin(JoinId),
55}
56
57impl std::fmt::Display for EvalError {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 match self {
60 EvalError::UnboundVar(v) => write!(f, "unbound variable: v_{}", v.0),
61 EvalError::ArityMismatch {
62 context,
63 expected,
64 got,
65 } => {
66 write!(
67 f,
68 "arity mismatch: expected {} {}, got {}",
69 expected, context, got
70 )
71 }
72 EvalError::TypeMismatch { expected, got } => {
73 write!(f, "type mismatch: expected {}, got {}", expected, got)
74 }
75 EvalError::NoMatchingAlt => write!(f, "no matching case alternative"),
76 EvalError::InfiniteLoop(id) => write!(f, "infinite loop: thunk {} forced itself", id.0),
77 EvalError::UnsupportedPrimOp(op) => write!(f, "unsupported primop: {:?}", op),
78 EvalError::HeapExhausted => write!(f, "heap exhausted"),
79 EvalError::NotAFunction => write!(f, "application of non-function value"),
80 EvalError::UnboundJoin(id) => write!(f, "jump to unbound join point: j_{}", id.0),
81 }
82 }
83}
84
85impl std::error::Error for EvalError {}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_error_display() {
93 let errs = vec![
94 EvalError::UnboundVar(VarId(42)),
95 EvalError::ArityMismatch {
96 context: "arguments",
97 expected: 2,
98 got: 1,
99 },
100 EvalError::TypeMismatch {
101 expected: "Int#",
102 got: ValueKind::Literal("Char#"),
103 },
104 EvalError::NoMatchingAlt,
105 EvalError::InfiniteLoop(ThunkId(0)),
106 EvalError::UnsupportedPrimOp(PrimOpKind::IntAdd),
107 EvalError::HeapExhausted,
108 EvalError::NotAFunction,
109 EvalError::UnboundJoin(JoinId(7)),
110 ];
111
112 for err in errs {
113 let s = format!("{}", err);
114 assert!(!s.is_empty(), "Display for {:?} should not be empty", err);
115 }
116 }
117}