1use cl_ast::{Expr, Sym, format::FmtAdapter};
5
6use crate::{closure::Closure, constructor::Constructor};
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 Str(Sym),
56 String(String),
58 Ref(usize),
60 Slice(usize, usize),
62 Array(Box<[ConValue]>),
64 Tuple(Box<[ConValue]>),
66 Struct(Sym, Box<HashMap<Sym, ConValue>>),
69 TupleStruct(Sym, Box<Box<[ConValue]>>),
71 Module(Box<HashMap<Sym, ConValue>>),
73 Quote(Rc<Expr>),
75 Function(Rc<Function>),
77 TupleConstructor(Constructor),
79 Closure(Rc<Closure>),
81 Builtin(&'static Builtin),
83}
84
85impl ConValue {
86 pub fn truthy(&self) -> IResult<bool> {
88 match self {
89 ConValue::Bool(v) => Ok(*v),
90 _ => Err(Error::TypeError())?,
91 }
92 }
93
94 pub fn typename(&self) -> &'static str {
95 match self {
96 ConValue::Empty => "Empty",
97 ConValue::Int(_) => "i64",
98 ConValue::Float(_) => "f64",
99 ConValue::Bool(_) => "bool",
100 ConValue::Char(_) => "char",
101 ConValue::Str(_) => "str",
102 ConValue::String(_) => "String",
103 ConValue::Ref(_) => "Ref",
104 ConValue::Slice(_, _) => "Slice",
105 ConValue::Array(_) => "Array",
106 ConValue::Tuple(_) => "Tuple",
107 ConValue::Struct(_, _) => "Struct",
108 ConValue::TupleStruct(_, _) => "TupleStruct",
109 ConValue::Module(_) => "",
110 ConValue::Quote(_) => "Quote",
111 ConValue::Function(_) => "Fn",
112 ConValue::TupleConstructor(_) => "Fn",
113 ConValue::Closure(_) => "Fn",
114 ConValue::Builtin(_) => "Fn",
115 }
116 }
117
118 #[allow(non_snake_case)]
119 pub fn TupleStruct(id: Sym, values: Box<[ConValue]>) -> Self {
120 Self::TupleStruct(id, Box::new(values))
121 }
122 #[allow(non_snake_case)]
123 pub fn Struct(id: Sym, values: HashMap<Sym, ConValue>) -> Self {
124 Self::Struct(id, Box::new(values))
125 }
126
127 pub fn index(&self, index: &Self, _env: &Environment) -> IResult<ConValue> {
128 let &Self::Int(index) = index else {
129 Err(Error::TypeError())?
130 };
131 match self {
132 ConValue::Str(string) => string
133 .chars()
134 .nth(index as _)
135 .map(ConValue::Char)
136 .ok_or(Error::OobIndex(index as usize, string.chars().count())),
137 ConValue::String(string) => string
138 .chars()
139 .nth(index as _)
140 .map(ConValue::Char)
141 .ok_or(Error::OobIndex(index as usize, string.chars().count())),
142 ConValue::Array(arr) => arr
143 .get(index as usize)
144 .cloned()
145 .ok_or(Error::OobIndex(index as usize, arr.len())),
146 &ConValue::Slice(id, len) => {
147 let index = if index < 0 {
148 len.wrapping_add_signed(index)
149 } else {
150 index as usize
151 };
152 if index < len {
153 Ok(ConValue::Ref(id + index))
154 } else {
155 Err(Error::OobIndex(index, len))
156 }
157 }
158 _ => Err(Error::TypeError()),
159 }
160 }
161 cmp! {
162 lt: false, <;
163 lt_eq: true, <=;
164 eq: true, ==;
165 neq: false, !=;
166 gt_eq: true, >=;
167 gt: false, >;
168 }
169 assign! {
170 add_assign: +;
171 bitand_assign: &;
172 bitor_assign: |;
173 bitxor_assign: ^;
174 div_assign: /;
175 mul_assign: *;
176 rem_assign: %;
177 shl_assign: <<;
178 shr_assign: >>;
179 sub_assign: -;
180 }
181}
182
183impl Callable for ConValue {
184 fn name(&self) -> Sym {
185 match self {
186 ConValue::Function(func) => func.name(),
187 ConValue::Closure(func) => func.name(),
188 ConValue::Builtin(func) => func.name(),
189 _ => "".into(),
190 }
191 }
192 fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
193 match self {
194 Self::Function(func) => func.call(env, args),
195 Self::TupleConstructor(func) => func.call(env, args),
196 Self::Closure(func) => func.call(env, args),
197 Self::Builtin(func) => func.call(env, args),
198 Self::Module(m) => {
199 if let Some(func) = m.get(&"call".into()) {
200 func.call(env, args)
201 } else {
202 Err(Error::NotCallable(self.clone()))
203 }
204 }
205 &Self::Ref(ptr) => {
206 let func = env.get_id(ptr).ok_or(Error::StackOverflow(ptr))?.clone();
208 func.call(env, args)
209 }
210 _ => Err(Error::NotCallable(self.clone())),
211 }
212 }
213}
214macro cmp ($($fn:ident: $empty:literal, $op:tt);*$(;)?) {$(
216 pub fn $fn(&self, other: &Self) -> IResult<Self> {
219 match (self, other) {
220 (Self::Empty, Self::Empty) => Ok(Self::Bool($empty)),
221 (Self::Int(a), Self::Int(b)) => Ok(Self::Bool(a $op b)),
222 (Self::Float(a), Self::Float(b)) => Ok(Self::Bool(a $op b)),
223 (Self::Bool(a), Self::Bool(b)) => Ok(Self::Bool(a $op b)),
224 (Self::Char(a), Self::Char(b)) => Ok(Self::Bool(a $op b)),
225 (Self::Str(a), Self::Str(b)) => Ok(Self::Bool(&**a $op &**b)),
226 (Self::Str(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
227 (Self::String(a), Self::Str(b)) => Ok(Self::Bool(&**a $op &**b)),
228 (Self::String(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
229 _ => Err(Error::TypeError())
230 }
231 }
232)*}
233macro assign($( $fn: ident: $op: tt );*$(;)?) {$(
234 pub fn $fn(&mut self, other: Self) -> IResult<()> {
235 *self = (std::mem::take(self) $op other)?;
236 Ok(())
237 }
238)*}
239macro from ($($T:ty => $v:expr),*$(,)?) {
241 $(impl From<$T> for ConValue {
242 fn from(value: $T) -> Self { $v(value.into()) }
243 })*
244}
245impl From<&Sym> for ConValue {
246 fn from(value: &Sym) -> Self {
247 ConValue::Str(*value)
248 }
249}
250from! {
251 Integer => ConValue::Int,
252 f64 => ConValue::Float,
253 bool => ConValue::Bool,
254 char => ConValue::Char,
255 Sym => ConValue::Str,
256 &str => ConValue::Str,
257 Expr => ConValue::Quote,
258 String => ConValue::String,
259 Rc<str> => ConValue::Str,
260 Function => ConValue::Function,
261 Vec<ConValue> => ConValue::Tuple,
262 &'static Builtin => ConValue::Builtin,
263}
264impl From<()> for ConValue {
265 fn from(_: ()) -> Self {
266 Self::Empty
267 }
268}
269impl From<&[ConValue]> for ConValue {
270 fn from(value: &[ConValue]) -> Self {
271 match value {
272 [] => Self::Empty,
273 [value] => value.clone(),
274 _ => Self::Tuple(value.into()),
275 }
276 }
277}
278
279macro ops($($trait:ty: $fn:ident = [$($match:tt)*])*) {
283 $(impl $trait for ConValue {
284 type Output = IResult<Self>;
285 fn $fn(self, rhs: Self) -> Self::Output {Ok(match (self, rhs) {$($match)*})}
287 })*
288}
289ops! {
290 Add: add = [
291 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
292 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_add(b)),
293 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a + b),
294 (ConValue::Str(a), ConValue::Str(b)) => (a.to_string() + &*b).into(),
295 (ConValue::Str(a), ConValue::String(b)) => (a.to_string() + &*b).into(),
296 (ConValue::String(a), ConValue::Str(b)) => (a.to_string() + &*b).into(),
297 (ConValue::String(a), ConValue::String(b)) => (a.to_string() + &*b).into(),
298 (ConValue::Str(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(c); s.into() }
299 (ConValue::String(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(c); s.into() }
300 (ConValue::Char(a), ConValue::Char(b)) => {
301 ConValue::String([a, b].into_iter().collect::<String>())
302 }
303 _ => Err(Error::TypeError())?
304 ]
305 BitAnd: bitand = [
306 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
307 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
308 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
309 _ => Err(Error::TypeError())?
310 ]
311 BitOr: bitor = [
312 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
313 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
314 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
315 _ => Err(Error::TypeError())?
316 ]
317 BitXor: bitxor = [
318 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
319 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
320 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
321 _ => Err(Error::TypeError())?
322 ]
323 Div: div = [
324 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
325 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.checked_div(b).unwrap_or_else(|| {
326 eprintln!("Warning: Divide by zero in {a} / {b}"); a
327 })),
328 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a / b),
329 _ => Err(Error::TypeError())?
330 ]
331 Mul: mul = [
332 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
333 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_mul(b)),
334 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a * b),
335 _ => Err(Error::TypeError())?
336 ]
337 Rem: rem = [
338 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
339 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.checked_rem(b).unwrap_or_else(|| {
340 println!("Warning: Divide by zero in {a} % {b}"); a
341 })),
342 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a % b),
343 _ => Err(Error::TypeError())?
344 ]
345 Shl: shl = [
346 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
347 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shl(b as _)),
348 _ => Err(Error::TypeError())?
349 ]
350 Shr: shr = [
351 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
352 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shr(b as _)),
353 _ => Err(Error::TypeError())?
354 ]
355 Sub: sub = [
356 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
357 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_sub(b)),
358 (ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a - b),
359 _ => Err(Error::TypeError())?
360 ]
361}
362impl std::fmt::Display for ConValue {
363 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
364 match self {
365 ConValue::Empty => "Empty".fmt(f),
366 ConValue::Int(v) => v.fmt(f),
367 ConValue::Float(v) => v.fmt(f),
368 ConValue::Bool(v) => v.fmt(f),
369 ConValue::Char(v) => v.fmt(f),
370 ConValue::Str(v) => v.fmt(f),
371 ConValue::String(v) => v.fmt(f),
372 ConValue::Ref(v) => write!(f, "&<{}>", v),
373 ConValue::Slice(id, len) => write!(f, "&<{id}>[{len}..]"),
374 ConValue::Array(array) => {
375 '['.fmt(f)?;
376 for (idx, element) in array.iter().enumerate() {
377 if idx > 0 {
378 ", ".fmt(f)?
379 }
380 element.fmt(f)?
381 }
382 ']'.fmt(f)
383 }
384 ConValue::Tuple(tuple) => {
385 '('.fmt(f)?;
386 for (idx, element) in tuple.iter().enumerate() {
387 if idx > 0 {
388 ", ".fmt(f)?
389 }
390 element.fmt(f)?
391 }
392 ')'.fmt(f)
393 }
394 ConValue::TupleStruct(id, tuple) => {
395 write!(f, "{id}")?;
396 '('.fmt(f)?;
397 for (idx, element) in tuple.iter().enumerate() {
398 if idx > 0 {
399 ", ".fmt(f)?
400 }
401 element.fmt(f)?
402 }
403 ')'.fmt(f)
404 }
405 ConValue::Struct(id, map) => {
406 use std::fmt::Write;
407 write!(f, "{id} ")?;
408 let mut f = f.delimit_with("{", "\n}");
409 for (k, v) in map.iter() {
410 write!(f, "\n{k}: {v},")?;
411 }
412 Ok(())
413 }
414 ConValue::Module(module) => {
415 use std::fmt::Write;
416 let mut f = f.delimit_with("{", "\n}");
417 for (k, v) in module.iter() {
418 write!(f, "\n{k}: {v},")?;
419 }
420 Ok(())
421 }
422 ConValue::Quote(q) => {
423 write!(f, "`{q}`")
424 }
425 ConValue::Function(func) => {
426 write!(f, "{}", func.decl())
427 }
428 ConValue::TupleConstructor(Constructor { name: index, arity }) => {
429 write!(f, "{index}(..{arity})")
430 }
431 ConValue::Closure(func) => {
432 write!(f, "{}", func.as_ref())
433 }
434 ConValue::Builtin(func) => {
435 write!(f, "{}", func)
436 }
437 }
438 }
439}
440
441pub macro cvstruct (
442 $Name:ident {
443 $($member:ident : $expr:expr),*
444 }
445) {{
446 let mut members = HashMap::new();
447 $(members.insert(stringify!($member).into(), ($expr).into());)*
448 ConValue::Struct(Box::new((stringify!($Name).into(), members)))
449}}