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
use std::fmt;
use std::error::Error;
use std::num::{ParseIntError, ParseFloatError};
#[derive(Debug, PartialEq)]
pub enum PartialComp {
Unary { op: String, arg: String },
Binary {
op: String,
lhs: String,
rhs: String,
},
}
impl PartialComp {
pub fn unary<T, U>(op: T, arg: U) -> Self
where T: ToString,
U: ToString
{
PartialComp::Unary {
op: op.to_string(),
arg: arg.to_string(),
}
}
pub fn binary<T, U, V>(op: T, lhs: U, rhs: V) -> Self
where T: ToString,
U: ToString,
V: ToString
{
PartialComp::Binary {
op: op.to_string(),
lhs: lhs.to_string(),
rhs: rhs.to_string(),
}
}
}
impl fmt::Display for PartialComp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PartialComp::Unary { ref op, ref arg } => {
write!(f, "{} {}", op, arg)
}
PartialComp::Binary {
ref op,
ref lhs,
ref rhs,
} => write!(f, "{} {} {}", lhs, op, rhs),
}
}
}
#[derive(Debug, PartialEq)]
pub enum CalcError {
BadTypes(PartialComp),
DivideByZero,
InvalidNumber(String),
InvalidOperator(char),
UnrecognizedToken(String),
UnexpectedToken(String, &'static str),
UnknownAtom(String),
UnexpectedEndOfInput,
UnmatchedParenthesis,
WouldOverflow(PartialComp),
WouldTruncate(PartialComp),
}
use CalcError::*;
impl fmt::Display for CalcError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
BadTypes(ref comp) => {
write!(f, "expression '{}' is not well typed", comp)
}
DivideByZero => write!(f, "attempted to divide by zero"),
InvalidNumber(ref number) => {
write!(f, "invalid number: {}", number)
}
InvalidOperator(ref c) => write!(f, "invalid operator: {}", c),
UnrecognizedToken(ref token) => {
write!(f, "unrecognized token: {}", token)
}
UnexpectedToken(ref token, ref kind) => {
write!(f, "expected {} token, got {} instead", kind, token)
}
UnknownAtom(ref atom) => {
write!(f, "unknown variable or function '{}'", atom)
}
WouldOverflow(ref comp) => {
write!(f, "expression '{}' would overflow", comp)
}
WouldTruncate(ref comp) => {
write!(f, "expression '{}' would be truncated", comp)
}
UnexpectedEndOfInput => write!(f, "unexpected end of input"),
UnmatchedParenthesis => write!(f, "unmatched patenthesis"),
}
}
}
impl From<ParseFloatError> for CalcError {
fn from(data: ParseFloatError) -> CalcError {
CalcError::InvalidNumber(data.description().into())
}
}
impl From<ParseIntError> for CalcError {
fn from(data: ParseIntError) -> CalcError {
CalcError::InvalidNumber(data.description().into())
}
}