1use std::fmt::{self, Display, Formatter};
2
3use crate::{
4 instruction::Type,
5 vm::{RuntimeError, RuntimeErrorKind},
6};
7
8#[derive(Clone, Copy, Debug, PartialEq)]
9pub enum Value {
10 Int(i64),
11 Bool(bool),
12 Char(u8),
13 Float(f64),
14 Ptr(Pointer),
15}
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum Pointer {
19 Rel(isize),
20 Abs(usize),
21}
22
23impl Display for Pointer {
24 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
25 match self {
26 Pointer::Rel(offset) => write!(f, "*rel[{offset}]"),
27 Pointer::Abs(addr) => write!(f, "*abs[{addr}]"),
28 }
29 }
30}
31
32impl Value {
33 pub(crate) fn unwrap_int(self) -> i64 {
34 match self {
35 Value::Int(value) => value,
36 _ => panic!("called `Value::unwrap_int` on a non-int value"),
37 }
38 }
39
40 pub(crate) fn unwrap_bool(self) -> bool {
41 match self {
42 Value::Bool(value) => value,
43 _ => panic!("called `Value::unwrap_bool` on a non-bool value"),
44 }
45 }
46
47 pub(crate) fn unwrap_ptr(self) -> Pointer {
48 match self {
49 Value::Ptr(ptr) => ptr,
50 _ => panic!("called `Value::unwrap_ptr` on a non-ptr value"),
51 }
52 }
53
54 pub(crate) fn neg(&self) -> Value {
55 match self {
56 Value::Int(val) => Value::Int(-val),
57 Value::Float(val) => Value::Float(-val),
58 _ => unreachable!("never called this way"),
59 }
60 }
61
62 pub(crate) fn not(&self) -> Value {
63 match self {
64 Value::Int(val) => Value::Int(!val),
65 Value::Bool(value) => Value::Bool(!value),
66 _ => unreachable!("never called this way"),
67 }
68 }
69
70 pub(crate) fn add(&self, rhs: Value) -> Value {
71 match (self, rhs) {
72 (Value::Int(lhs), Value::Int(rhs)) => Value::Int(lhs.wrapping_add(rhs)),
73 (Value::Char(lhs), Value::Char(rhs)) => Value::Char(lhs.wrapping_add(rhs) & 0x7f),
74 (Value::Float(lhs), Value::Float(rhs)) => Value::Float(lhs + rhs),
75 _ => unreachable!("other types do not support this operation: {self} + {rhs}"),
76 }
77 }
78
79 pub(crate) fn sub(&self, rhs: Value) -> Value {
80 match (self, rhs) {
81 (Value::Int(lhs), Value::Int(rhs)) => Value::Int(lhs.wrapping_sub(rhs)),
82 (Value::Char(lhs), Value::Char(rhs)) => Value::Char(lhs.wrapping_sub(rhs) & 0x7f),
83 (Value::Float(lhs), Value::Float(rhs)) => Value::Float(lhs - rhs),
84 _ => unreachable!("other types do not support this operation: {self} - {rhs}"),
85 }
86 }
87
88 pub(crate) fn mul(&self, rhs: Value) -> Value {
89 match (self, rhs) {
90 (Value::Int(lhs), Value::Int(rhs)) => Value::Int(lhs.wrapping_mul(rhs)),
91 (Value::Float(lhs), Value::Float(rhs)) => Value::Float(lhs * rhs),
92 _ => unreachable!("other types do not support this operation: {self} * {rhs}"),
93 }
94 }
95
96 pub(crate) fn pow(&self, rhs: Value) -> Value {
97 Value::Int(self.unwrap_int().wrapping_pow(rhs.unwrap_int() as u32))
98 }
99
100 pub(crate) fn div(&self, rhs: Value) -> Result<Value, RuntimeError> {
101 match (self, rhs) {
102 (_, Value::Int(0)) => Err(RuntimeError::new(
103 RuntimeErrorKind::Arithmetic,
104 format!("{self} / {rhs} is illegal"),
105 )),
106 (Value::Int(lhs), Value::Int(rhs)) => Ok(Value::Int(lhs.wrapping_div(rhs))),
107 (Value::Float(lhs), Value::Float(rhs)) => Ok(Value::Float(lhs / rhs)),
108 _ => unreachable!("other types do not support this operation: {self} / {rhs}"),
109 }
110 }
111
112 pub(crate) fn rem(&self, rhs: Value) -> Result<Value, RuntimeError> {
113 match (self, rhs) {
114 (_, Value::Int(0)) => Err(RuntimeError::new(
115 RuntimeErrorKind::Arithmetic,
116 format!("{self} % {rhs} is illegal"),
117 )),
118 (Value::Int(lhs), Value::Int(rhs)) => Ok(Value::Int(lhs.wrapping_rem(rhs))),
119 _ => unreachable!("other types do not support this operation: {self} % {rhs}"),
120 }
121 }
122
123 pub(crate) fn eq(&self, rhs: Value) -> Value {
124 Value::Bool(*self == rhs)
125 }
126
127 pub(crate) fn ne(&self, rhs: Value) -> Value {
128 Value::Bool(*self != rhs)
129 }
130
131 pub(crate) fn lt(&self, rhs: Value) -> Value {
132 let res = match (self, rhs) {
133 (Value::Int(lhs), Value::Int(rhs)) => *lhs < rhs,
134 (Value::Float(lhs), Value::Float(rhs)) => *lhs < rhs,
135 (Value::Char(lhs), Value::Char(rhs)) => *lhs < rhs,
136 _ => unreachable!("other types cannot be compared: {self} < {rhs}"),
137 };
138 Value::Bool(res)
139 }
140
141 pub(crate) fn le(&self, rhs: Value) -> Value {
142 let res = match (self, rhs) {
143 (Value::Int(lhs), Value::Int(rhs)) => *lhs <= rhs,
144 (Value::Float(lhs), Value::Float(rhs)) => *lhs <= rhs,
145 (Value::Char(lhs), Value::Char(rhs)) => *lhs <= rhs,
146 _ => unreachable!("other types cannot be compared: {self} <= {rhs}"),
147 };
148 Value::Bool(res)
149 }
150
151 pub(crate) fn gt(&self, rhs: Value) -> Value {
152 let res = match (self, rhs) {
153 (Value::Int(lhs), Value::Int(rhs)) => *lhs > rhs,
154 (Value::Float(lhs), Value::Float(rhs)) => *lhs > rhs,
155 (Value::Char(lhs), Value::Char(rhs)) => *lhs > rhs,
156 _ => unreachable!("other types cannot be compared: {self} > {rhs}"),
157 };
158 Value::Bool(res)
159 }
160
161 pub(crate) fn ge(&self, rhs: Value) -> Value {
162 let res = match (self, rhs) {
163 (Value::Int(lhs), Value::Int(rhs)) => *lhs >= rhs,
164 (Value::Float(lhs), Value::Float(rhs)) => *lhs >= rhs,
165 (Value::Char(lhs), Value::Char(rhs)) => *lhs >= rhs,
166 _ => unreachable!("other types cannot be compared: {self} >= {rhs}"),
167 };
168 Value::Bool(res)
169 }
170
171 pub(crate) fn shl(&self, rhs: Value) -> Result<Value, RuntimeError> {
172 let (Value::Int(lhs), Value::Int(rhs)) = (self, rhs) else {
173 unreachable!("other types cannot be shifted: {self} << {rhs}");
174 };
175 if !(0..=63).contains(&rhs) {
176 return Err(RuntimeError::new(
177 RuntimeErrorKind::Arithmetic,
178 "rhs is not in range `0..=63`".to_string(),
179 ));
180 }
181 Ok(Value::Int(lhs << rhs as u32))
182 }
183
184 pub(crate) fn shr(&self, rhs: Value) -> Result<Value, RuntimeError> {
185 let (Value::Int(lhs), Value::Int(rhs)) = (self, rhs) else {
186 unreachable!("other types cannot be shifted: {self} >> {rhs}");
187 };
188 if !(0..=63).contains(&rhs) {
189 return Err(RuntimeError::new(
190 RuntimeErrorKind::Arithmetic,
191 "rhs is not in range `0..=63`".to_string(),
192 ));
193 }
194 Ok(Value::Int(lhs >> rhs as u32))
195 }
196
197 pub(crate) fn bit_or(&self, rhs: Value) -> Value {
198 match (self, rhs) {
199 (Value::Int(lhs), Value::Int(rhs)) => Value::Int(lhs | rhs),
200 (Value::Bool(lhs), Value::Bool(rhs)) => Value::Bool(lhs | rhs),
201 _ => unreachable!("other types are illegal: {self} | {rhs}"),
202 }
203 }
204
205 pub(crate) fn bit_and(&self, rhs: Value) -> Value {
206 match (self, rhs) {
207 (Value::Int(lhs), Value::Int(rhs)) => Value::Int(lhs & rhs),
208 (Value::Bool(lhs), Value::Bool(rhs)) => Value::Bool(lhs & rhs),
209 _ => unreachable!("other types are illegal: {self} & {rhs}"),
210 }
211 }
212
213 pub(crate) fn bit_xor(&self, rhs: Value) -> Value {
214 match (self, rhs) {
215 (Value::Int(lhs), Value::Int(rhs)) => Value::Int(lhs ^ rhs),
216 (Value::Bool(lhs), Value::Bool(rhs)) => Value::Bool(lhs ^ rhs),
217 _ => unreachable!("other types are illegal: {self} ^ {rhs}"),
218 }
219 }
220
221 pub(crate) fn cast(self, to: Type) -> Value {
222 match to {
223 Type::Int => self.cast_int(),
224 Type::Bool => self.cast_bool(),
225 Type::Char => self.cast_char(),
226 Type::Float => self.cast_float(),
227 }
228 }
229
230 fn cast_int(self) -> Value {
231 let res = match self {
232 Value::Bool(val) => val as i64,
233 Value::Char(val) => val as i64,
234 Value::Float(val) => val as i64,
235 _ => unreachable!("other combinations are impossible: {self} as int"),
236 };
237 Value::Int(res)
238 }
239
240 fn cast_bool(self) -> Value {
241 let res = match self {
242 Value::Int(val) => val != 0,
243 Value::Char(val) => val != 0,
244 Value::Float(val) => val != 0.0,
245 _ => unreachable!("other combinations are impossible: {self} as bool"),
246 };
247 Value::Bool(res)
248 }
249
250 fn cast_char(self) -> Value {
251 let res = match self {
252 Value::Int(i64::MIN..=0) => 0,
253 Value::Int(127..=i64::MAX) => 127,
254 Value::Int(val) => val as u8,
255 Value::Bool(val) => val as u8,
256 Value::Float(val) if val < 0.0 => 0,
257 Value::Float(val) if val > 127.0 => 127,
258 Value::Float(val) => val as u8,
259 _ => unreachable!("other combinations are impossible: {self} as char"),
260 };
261 Value::Char(res)
262 }
263
264 fn cast_float(self) -> Value {
265 let res = match self {
266 Value::Int(val) => val as f64,
267 Value::Bool(val) => val as u8 as f64,
268 Value::Char(val) => val as f64,
269 _ => unreachable!("other combinations are impossible: {self} as float"),
270 };
271 Value::Float(res)
272 }
273}
274
275impl Display for Value {
276 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
277 match self {
278 Value::Int(val) => write!(f, "{val}"),
279 Value::Bool(val) => write!(f, "{val}"),
280 Value::Char(val) => write!(f, "{val}"),
281 Value::Float(val) => write!(
282 f,
283 "{val}{zero}",
284 zero = if val.fract() == 0.0 { ".0" } else { "" }
285 ),
286 Value::Ptr(ptr) => match ptr {
287 Pointer::Rel(offset) => write!(f, "*rel[{offset}]"),
288 Pointer::Abs(addr) => write!(f, "*abs[{addr}]"),
289 },
290 }
291 }
292}