1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
use crate::lisp::{
expr::Arity,
lex::{Span, SpanDisplay},
};
use std::fmt;
#[derive(Debug, PartialEq, Clone)]
pub enum LispError {
Parse(ParseError),
Eval(EvalError),
}
impl fmt::Display for LispError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Parse(p) => write!(f, "parse error: {}", p.kind),
Self::Eval(e) => write!(f, "eval error: {}", e),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct ParseError {
pub span: Span,
pub kind: ParseErrorKind,
}
impl ParseError {
pub fn new(span: Span, kind: ParseErrorKind) -> Self {
Self { span, kind }
}
pub fn fmt(&self, f: &mut fmt::Formatter<'_>, text: &str) -> fmt::Result {
let SpanDisplay { line, col, .. } = SpanDisplay::highlight_span(self.span, text);
write!(f, "line {}, col {}: {}", line, col, self.kind)
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum ParseErrorKind {
InvalidLiteral,
InvalidToken,
InvalidChar(char),
LiteralParseError,
MissingCloseParen,
UnbalancedComma,
UnexpectedEof,
UnexpectedToken {
expected: &'static str,
found: &'static str,
},
UnmatchedParen,
UnterminatedString,
}
impl fmt::Display for ParseErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ParseErrorKind::InvalidChar(ch) => write!(f, "invalid character {}", ch),
ParseErrorKind::InvalidToken => write!(f, "invalid token"),
ParseErrorKind::UnexpectedEof => write!(f, "unexpected end of file"),
ParseErrorKind::InvalidLiteral => write!(f, "invalid literal"),
ParseErrorKind::UnmatchedParen => write!(f, "unmatched `)`"),
ParseErrorKind::UnbalancedComma => write!(f, "unbalanced comma"),
ParseErrorKind::UnexpectedToken { expected, found } => {
write!(
f,
"unexpected token, got `{}`, expected `{}`",
found, expected
)
}
ParseErrorKind::LiteralParseError => write!(f, "error parsing literal"),
ParseErrorKind::MissingCloseParen => write!(f, "missing `)`"),
ParseErrorKind::UnterminatedString => write!(f, "unterminated string literal"),
}
}
}
impl From<ParseError> for LispError {
fn from(p: ParseError) -> Self {
LispError::Parse(p)
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum EvalError {
ArgumentCount(Arity),
BadForm,
UnboundVariable(String),
DivByZero,
TypeMismatch,
NoFileName,
CustomInternal(&'static str),
}
impl fmt::Display for EvalError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ArgumentCount(i) => {
write!(f, "invalid number of arguments, expected ")?;
match i {
Arity::Exact(a) => write!(f, "exactly {} argument(s)", a),
Arity::Atleast(a) => write!(f, "atleast {} argument(s)", a),
Arity::Atmost(a) => write!(f, "atmost {} argument(s)", a),
Arity::Range(low, high) => {
write!(f, "between {} and {} argument(s)", low, high)
}
Arity::None => write!(f, "any number of arguments"),
}
}
Self::BadForm => write!(f, "bad expression form"),
Self::UnboundVariable(s) => write!(f, "unbound variable {}", s),
Self::TypeMismatch => write!(f, "mismatched types"),
Self::DivByZero => write!(f, "attempt to divide by zero"),
Self::NoFileName => write!(f, "no file name specified"),
Self::CustomInternal(s) => write!(f, "{}", s),
}
}
}
impl From<EvalError> for LispError {
fn from(e: EvalError) -> Self {
LispError::Eval(e)
}
}
|