1use cl_ast::{Expr, Sym, format::FmtAdapter};
5
6use crate::{closure::Closure, env::Place};
7
8use super::{
9 Callable, Environment,
10 builtin::Builtin,
11 error::{Error, IResult},
12 function::Function,
13};
14use std::{collections::HashMap, ops::*, rc::Rc};
15
16type Integer = isize;
39
40#[derive(Clone, Debug, Default)]
42pub enum ConValue {
43 #[default]
45 Empty,
46 Int(Integer),
48 Float(f64),
50 Bool(bool),
52 Char(char),
54 String(Sym),
56 Ref(Place),
58 Slice(Place, usize),
60 Array(Box<[ConValue]>),
62 Tuple(Box<[ConValue]>),
64 Struct(Box<(Sym, HashMap<Sym, ConValue>)>),
66 TupleStruct(Box<(&'static str, Box<[ConValue]>)>),
68 Module(Box<HashMap<Sym, Option<ConValue>>>),
70 Quote(Box<Expr>),
72 Function(Rc<Function>),
74 Closure(Rc<Closure>),
76 Builtin(&'static Builtin),
78}
79
80impl ConValue {
81 pub fn truthy(&self) -> IResult<bool> {
83 match self {
84 ConValue::Bool(v) => Ok(*v),
85 _ => Err(Error::TypeError())?,
86 }
87 }
88
89 #[allow(non_snake_case)]
90 pub fn TupleStruct(name: Sym, values: Box<[ConValue]>) -> Self {
91 Self::TupleStruct(Box::new((name.to_ref(), values)))
92 }
93 #[allow(non_snake_case)]
94 pub fn Struct(name: Sym, values: HashMap<Sym, ConValue>) -> Self {
95 Self::Struct(Box::new((name, values)))
96 }
97
98 pub fn index(&self, index: &Self, env: &Environment) -> IResult<ConValue> {
99 let Self::Int(index) = index else {
100 Err(Error::TypeError())?
101 };
102 match self {
103 ConValue::String(string) => string
104 .chars()
105 .nth(*index as _)
106 .map(ConValue::Char)
107 .ok_or(Error::OobIndex(*index as usize, string.chars().count())),
108 ConValue::Array(arr) => arr
109 .get(*index as usize)
110 .cloned()
111 .ok_or(Error::OobIndex(*index as usize, arr.len())),
112 ConValue::Slice(id, start) => env
113 .get_id(*id)
114 .ok_or(Error::StackOverflow(*id))?
115 .index(&ConValue::Int((*index as usize + start) as isize), env),
116 _ => Err(Error::TypeError()),
117 }
118 }
119 cmp! {
120 lt: false, <;
121 lt_eq: true, <=;
122 eq: true, ==;
123 neq: false, !=;
124 gt_eq: true, >=;
125 gt: false, >;
126 }
127 assign! {
128 add_assign: +;
129 bitand_assign: &;
130 bitor_assign: |;
131 bitxor_assign: ^;
132 div_assign: /;
133 mul_assign: *;
134 rem_assign: %;
135 shl_assign: <<;
136 shr_assign: >>;
137 sub_assign: -;
138 }
139}
140
141impl Callable for ConValue {
142 fn name(&self) -> Sym {
143 match self {
144 ConValue::Function(func) => func.name(),
145 ConValue::Closure(func) => func.name(),
146 ConValue::Builtin(func) => func.name(),
147 _ => "".into(),
148 }
149 }
150 fn call(&self, interpreter: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
151 match self {
152 Self::Function(func) => func.call(interpreter, args),
153 Self::Closure(func) => func.call(interpreter, args),
154 Self::Builtin(func) => func.call(interpreter, args),
155 _ => Err(Error::NotCallable(self.clone())),
156 }
157 }
158}
159macro cmp ($($fn:ident: $empty:literal, $op:tt);*$(;)?) {$(
161 pub fn $fn(&self, other: &Self) -> IResult<Self> {
164 match (self, other) {
165 (Self::Empty, Self::Empty) => Ok(Self::Bool($empty)),
166 (Self::Int(a), Self::Int(b)) => Ok(Self::Bool(a $op b)),
167 (Self::Float(a), Self::Float(b)) => Ok(Self::Bool(a $op b)),
168 (Self::Bool(a), Self::Bool(b)) => Ok(Self::Bool(a $op b)),
169 (Self::Char(a), Self::Char(b)) => Ok(Self::Bool(a $op b)),
170 (Self::String(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
171 _ => Err(Error::TypeError())
172 }
173 }
174)*}
175macro assign($( $fn: ident: $op: tt );*$(;)?) {$(
176 pub fn $fn(&mut self, other: Self) -> IResult<()> {
177 *self = (std::mem::take(self) $op other)?;
178 Ok(())
179 }
180)*}
181macro from ($($T:ty => $v:expr),*$(,)?) {
183 $(impl From<$T> for ConValue {
184 fn from(value: $T) -> Self { $v(value.into()) }
185 })*
186}
187impl From<&Sym> for ConValue {
188 fn from(value: &Sym) -> Self {
189 ConValue::String(*value)
190 }
191}
192from! {
193 Integer => ConValue::Int,
194 f64 => ConValue::Float,
195 bool => ConValue::Bool,
196 char => ConValue::Char,
197 Sym => ConValue::String,
198 &str => ConValue::String,
199 Expr => ConValue::Quote,
200 String => ConValue::String,
201 Rc<str> => ConValue::String,
202 Function => ConValue::Function,
203 Vec<ConValue> => ConValue::Tuple,
204 &'static Builtin => ConValue::Builtin,
205}
206impl From<()> for ConValue {
207 fn from(_: ()) -> Self {
208 Self::Empty
209 }
210}
211impl From<&[ConValue]> for ConValue {
212 fn from(value: &[ConValue]) -> Self {
213 match value {
214 [] => Self::Empty,
215 [value] => value.clone(),
216 _ => Self::Tuple(value.into()),
217 }
218 }
219}
220
221macro ops($($trait:ty: $fn:ident = [$($match:tt)*])*) {
225 $(impl $trait for ConValue {
226 type Output = IResult<Self>;
227 fn $fn(self, rhs: Self) -> Self::Output {Ok(match (self, rhs) {$($match)*})}
229 })*
230}
231ops! {
232 Add: add = [
233 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
234 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_add(b)),
235 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a + b),
236 (ConValue::String(a), ConValue::String(b)) => (a.to_string() + &*b).into(),
237 (ConValue::String(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(c); s.into() }
238 (ConValue::Char(a), ConValue::Char(b)) => {
239 ConValue::String([a, b].into_iter().collect::<String>().into())
240 }
241 _ => Err(Error::TypeError())?
242 ]
243 BitAnd: bitand = [
244 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
245 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
246 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
247 _ => Err(Error::TypeError())?
248 ]
249 BitOr: bitor = [
250 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
251 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
252 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
253 _ => Err(Error::TypeError())?
254 ]
255 BitXor: bitxor = [
256 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
257 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
258 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
259 _ => Err(Error::TypeError())?
260 ]
261 Div: div = [
262 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
263 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.checked_div(b).unwrap_or_else(|| {
264 eprintln!("Warning: Divide by zero in {a} / {b}"); a
265 })),
266 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a / b),
267 _ => Err(Error::TypeError())?
268 ]
269 Mul: mul = [
270 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
271 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_mul(b)),
272 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a * b),
273 _ => Err(Error::TypeError())?
274 ]
275 Rem: rem = [
276 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
277 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.checked_rem(b).unwrap_or_else(|| {
278 println!("Warning: Divide by zero in {a} % {b}"); a
279 })),
280 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a % b),
281 _ => Err(Error::TypeError())?
282 ]
283 Shl: shl = [
284 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
285 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shl(b as _)),
286 _ => Err(Error::TypeError())?
287 ]
288 Shr: shr = [
289 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
290 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shr(b as _)),
291 _ => Err(Error::TypeError())?
292 ]
293 Sub: sub = [
294 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
295 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_sub(b)),
296 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a - b),
297 _ => Err(Error::TypeError())?
298 ]
299}
300impl std::fmt::Display for ConValue {
301 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
302 match self {
303 ConValue::Empty => "Empty".fmt(f),
304 ConValue::Int(v) => v.fmt(f),
305 ConValue::Float(v) => v.fmt(f),
306 ConValue::Bool(v) => v.fmt(f),
307 ConValue::Char(v) => v.fmt(f),
308 ConValue::String(v) => v.fmt(f),
309 ConValue::Ref(v) => write!(f, "&<{}>", v),
310 ConValue::Slice(v, len) => write!(f, "&<{v}>[{len}..]"),
311 ConValue::Array(array) => {
312 '['.fmt(f)?;
313 for (idx, element) in array.iter().enumerate() {
314 if idx > 0 {
315 ", ".fmt(f)?
316 }
317 element.fmt(f)?
318 }
319 ']'.fmt(f)
320 }
321 ConValue::Tuple(tuple) => {
322 '('.fmt(f)?;
323 for (idx, element) in tuple.iter().enumerate() {
324 if idx > 0 {
325 ", ".fmt(f)?
326 }
327 element.fmt(f)?
328 }
329 ')'.fmt(f)
330 }
331 ConValue::TupleStruct(parts) => {
332 let (name, tuple) = parts.as_ref();
333 if !name.is_empty() {
334 write!(f, "{name}")?;
335 }
336 '('.fmt(f)?;
337 for (idx, element) in tuple.iter().enumerate() {
338 if idx > 0 {
339 ", ".fmt(f)?
340 }
341 element.fmt(f)?
342 }
343 ')'.fmt(f)
344 }
345 ConValue::Struct(parts) => {
346 let (name, map) = parts.as_ref();
347 use std::fmt::Write;
348 if !name.is_empty() {
349 write!(f, "{name} ")?;
350 }
351 let mut f = f.delimit_with("{", "\n}");
352 for (k, v) in map.iter() {
353 write!(f, "\n{k}: {v},")?;
354 }
355 Ok(())
356 }
357 ConValue::Module(module) => {
358 use std::fmt::Write;
359 let mut f = f.delimit_with("{", "\n}");
360 for (k, v) in module.iter() {
361 write!(f, "\n{k}: ")?;
362 match v {
363 Some(v) => write!(f, "{v},"),
364 None => write!(f, "_,"),
365 }?
366 }
367 Ok(())
368 }
369 ConValue::Quote(q) => {
370 write!(f, "`{q}`")
371 }
372 ConValue::Function(func) => {
373 write!(f, "{}", func.decl())
374 }
375 ConValue::Closure(func) => {
376 write!(f, "{}", func.as_ref())
377 }
378 ConValue::Builtin(func) => {
379 write!(f, "{}", func.description())
380 }
381 }
382 }
383}
384
385pub macro cvstruct (
386 $Name:ident {
387 $($member:ident : $expr:expr),*
388 }
389) {{
390 let mut members = HashMap::new();
391 $(members.insert(stringify!($member).into(), ($expr).into());)*
392 ConValue::Struct(Box::new((stringify!($Name).into(), members)))
393}}