1#![allow(non_upper_case_globals)]
3
4use cl_ast::types::Symbol;
5
6use crate::{
7 Callable,
8 convalue::ConValue,
9 env::Environment,
10 error::{Error, ErrorKind, IResult},
11 place::Place,
12};
13use std::io::{Write, stdout};
14
15#[derive(Clone, Copy)]
17pub struct Builtin {
18 pub name: &'static str,
20 pub desc: &'static str,
22 pub func: &'static dyn Fn(&mut Environment, &[ConValue]) -> IResult<ConValue>,
24}
25
26impl Builtin {
27 pub const fn new(
29 name: &'static str,
30 desc: &'static str,
31 func: &'static impl Fn(&mut Environment, &[ConValue]) -> IResult<ConValue>,
32 ) -> Builtin {
33 Builtin { name, desc, func }
34 }
35
36 pub const fn description(&self) -> &'static str {
37 self.desc
38 }
39}
40
41impl std::fmt::Debug for Builtin {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 f.debug_struct("Builtin")
44 .field("description", &self.desc)
45 .finish_non_exhaustive()
46 }
47}
48
49impl std::fmt::Display for Builtin {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 f.write_str(self.desc)
52 }
53}
54
55impl super::Callable for Builtin {
56 fn call(&self, interpreter: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
57 (self.func)(interpreter, args)
58 }
59
60 fn name(&self) -> Option<Symbol> {
61 Some(self.name.into())
62 }
63}
64
65pub macro builtin(
83 $(#[$($meta:tt)*])*
84 fn $name:ident ($($arg:pat),*$(,)?) $(@$env:tt)? $body:block
85) {{
86 $(#[$($meta)*])*
87 fn $name(_env: &mut Environment, _args: &[ConValue]) -> IResult<ConValue> {
88 $(#[allow(unused)]let $env = _env;)?
90 #[allow(clippy::redundant_at_rest_pattern, irrefutable_let_patterns)]
92 let [$($arg),*] = _args else {
93 Err($crate::error::Error::TypeError(concat!("(", $(stringify!($arg,),)* ")"), "something weird"))?
94 };
95 $body.map(Into::into)
96 }
97 Builtin {
98 name: stringify!($name),
99 desc: stringify![builtin fn $name($($arg),*)],
100 func: &$name,
101 }
102}}
103
104pub macro builtins($(
106 $(#[$($meta:tt)*])*
107 fn $name:ident ($($args:tt)*) $(@$env:tt)? $body:block
108)*) {
109 [$(builtin!($(#[$($meta)*])* fn $name ($($args)*) $(@$env)? $body)),*]
110}
111
112pub macro error_format ($($t:tt)*) {
115 $crate::error::Error::BuiltinError(format!($($t)*))
116}
117
118pub const Builtins: &[Builtin] = &builtins![
119 fn fmt(args @ ..) @env {
121 use std::fmt::Write;
122 let mut out = String::new();
123
124 for mut arg in args.iter() {
125 while let ConValue::Ref(r) = arg {
126 arg = r.get(env)?;
127 }
128 if let Err(e) = write!(out, "{arg}") {
129 eprintln!("{e}");
130 }
131 }
132 Ok(out)
133 }
134
135 fn print(args @ ..) @env {
137 let mut out = stdout().lock();
138 for mut arg in args.iter() {
139 while let ConValue::Ref(r) = arg {
140 arg = r.get(env)?;
141 }
142 write!(out, "{arg}").ok();
143 }
144 Ok(())
145 }
146
147 fn println(args @ ..) @env {
149 let mut out = stdout().lock();
150 for mut arg in args.iter() {
151 while let ConValue::Ref(r) = arg {
152 arg = r.get(env)?;
153 }
154 write!(out, "{arg}").ok();
155 }
156 writeln!(out).ok();
157 Ok(())
158 }
159
160 fn dbg(arg) {
162 println!("{arg:?}");
163 Ok(arg.clone())
164 }
165
166 fn dbgp(args @ ..) {
168 let mut out = stdout().lock();
169 args.iter().try_for_each(|arg| writeln!(out, "{arg:#?}") ).ok();
170 Ok(())
171 }
172
173 fn bind(ConValue::Str(name), value) @env {
174 env.bind(*name, value.clone());
175 Ok(())
176 }
177
178 fn raw_ref(ConValue::Int(index)) {
180 Ok(ConValue::Ref(Place::from_index(*index as _)))
181 }
182
183 fn panic(args @ ..) @env {
184 use std::fmt::Write;
185 let mut stdout = stdout().lock();
186 let mut out = String::from("Explicit panic: ");
187 if let Err(e) = args.iter().try_for_each(|arg| write!(out, "{arg}")) {
188 writeln!(stdout, "{e}").ok();
189 }
190 writeln!(stdout, "{out}");
191 Err(Error::Panic(out))?;
192 Ok(())
193 }
194
195 fn todo(args @ ..) @env {
196 use std::fmt::Write;
197 let mut stdout = stdout().lock();
198 let mut out = String::from("Not yet implemented: ");
199 if let Err(e) = args.iter().try_for_each(|arg| write!(out, "{arg}")) {
200 writeln!(stdout, "{e}").ok();
201 }
202 writeln!(stdout, "{out}");
203 Err(Error::Panic(out))?;
204 Ok(())
205 }
206
207 fn dump() @env {
209 println!("{env}");
210 Ok(())
211 }
212
213 fn backtrace() @env {
214 println!("Backtrace:\n{}", env.backtrace());
215 Ok(())
216 }
217
218 fn host_backtrace() {
219 println!("Host backtrace:\n{}", std::backtrace::Backtrace::force_capture());
220 Ok(())
221 }
222
223 fn builtins() @env {
224 let len = env.globals().binds.len();
225 for builtin in 0..len {
226 if let Some(value @ ConValue::Builtin(_)) = env.get_id(builtin) {
227 println!("{builtin}: {value}")
228 }
229 }
230 Ok(())
231 }
232
233 fn len(list) @env {
235 Ok(match list.dereference_in(env)? {
236 ConValue::Empty => 0,
237 ConValue::Str(s) => s.chars().count() as _,
238 ConValue::String(s) => s.chars().count() as _,
239 ConValue::Slice(_, len) => *len as _,
240 ConValue::Array(arr) => arr.len() as _,
241 ConValue::Tuple(t) => t.len() as _,
242 other => Err(Error::TypeError("A type with a length", other.typename()))?,
243 })
244 }
245
246 fn push(ConValue::Ref(index), item) @env{
247 let mut index = index.get_mut(env)?;
248 while let ConValue::Ref(r) = index {
249 index = r.clone().get_mut(env)?;
250 }
251 let ConValue::Array(v) = index else {
252 Err(Error::TypeError("An array", index.typename()))?
253 };
254
255 let mut items = std::mem::take(v).into_vec();
256 items.push(item.clone());
257 *v = items.into_boxed_slice();
258
259 Ok(ConValue::Empty)
260 }
261
262 fn pop(ConValue::Ref(index)) @env {
263 let v = match index.get_mut(env)? {
264 ConValue::Array(v) => v,
265 other => Err(Error::TypeError("An array", other.typename()))?,
266 };
267
268 let mut items = std::mem::take(v).into_vec();
269 let out = items.pop().unwrap_or(ConValue::Empty);
270 *v = items.into_boxed_slice();
271
272 Ok(out)
273 }
274
275 fn chars(string) @env {
276 Ok(match string.dereference_in(env)? {
277 ConValue::Str(s) => ConValue::Array(s.chars().map(Into::into).collect()),
278 ConValue::String(s) => ConValue::Array(s.chars().map(Into::into).collect()),
279 _ => Err(Error::TypeError("string", string.typename()))?,
280 })
281 }
282
283 fn invoke(function, args) @env {
285 match args {
286 ConValue::Empty => function.call(env, &[]),
287 ConValue::Array(args) | ConValue::Tuple(args) => function.call(env, args),
288 _ => function.call(env, std::slice::from_ref(args)),
289 }
290 }
291
292 fn dump_symbols() {
293 println!("{}", cl_structures::intern::string_interner::StringInterner::global());
294 Ok(ConValue::Empty)
295 }
296
297 fn catch_panic(lambda, args @ ..) @env {
298 match lambda.call(env, args) {
299 Err(Error { kind: ErrorKind::Panic(e, ..), ..}) => {
300 println!("Caught panic!");
301 Ok(ConValue::String(e))
302 },
303 other => other,
304 }
305 }
306
307 fn shark() {
309 Ok('\u{1f988}')
310 }
311];
312
313pub const Math: &[Builtin] = &builtins![
314 fn mul(lhs, rhs) {
316 Ok(match (lhs, rhs) {
317 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
318 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a * b),
319 _ => Err(Error::TypeError("type implements Mul", lhs.typename()))?,
320 })
321 }
322
323 fn div(lhs, rhs) {
325 Ok(match (lhs, rhs){
326 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
327 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a / b),
328 _ => Err(Error::TypeError("type implements Div", lhs.typename()))?,
329 })
330 }
331
332 fn rem(lhs, rhs) {
334 Ok(match (lhs, rhs) {
335 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
336 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a % b),
337 _ => Err(Error::TypeError("type implements Rem", lhs.typename()))?,
338 })
339 }
340
341 fn add(lhs, rhs) {
343 Ok(match (lhs, rhs) {
344 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
345 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b),
346 (ConValue::Str(a), ConValue::Str(b)) => (a.to_string() + b).into(),
347 (ConValue::Str(a), ConValue::String(b)) => (a.to_string() + b).into(),
348 (ConValue::String(a), ConValue::Str(b)) => (a.to_string() + b).into(),
349 (ConValue::String(a), ConValue::String(b)) => (a.to_string() + b).into(),
350 (ConValue::Str(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(*c); s.into() }
351 (ConValue::String(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(*c); s.into() }
352 (ConValue::Char(a), ConValue::Char(b)) => {
353 ConValue::String([a, b].into_iter().collect())
354 }
355 _ => Err(Error::TypeError("type implements Add", lhs.typename()))?,
356 })
357 }
358
359 fn sub(lhs, rhs) {
361 Ok(match (lhs, rhs) {
362 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
363 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a - b),
364 _ => Err(Error::TypeError("type implements Sub", lhs.typename()))?,
365 })
366 }
367
368 fn shl(lhs, rhs) {
370 Ok(match (lhs, rhs) {
371 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
372 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a << b),
373 (ConValue::Int(a), b) => Err(Error::TypeError("int", b.typename()))?,
374 _ => Err(Error::TypeError("type implements Shl", lhs.typename()))?,
375 })
376 }
377
378 fn shr(lhs, rhs) {
380 Ok(match (lhs, rhs) {
381 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
382 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a >> b),
383 (ConValue::Int(a), b) => Err(Error::TypeError("int", b.typename()))?,
384 _ => Err(Error::TypeError("type implements Shr", lhs.typename()))?,
385 })
386 }
387
388 fn and(lhs, rhs) {
390 Ok(match (lhs, rhs) {
391 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
392 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
393 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
394 _ => Err(Error::TypeError("type implements BitAnd", lhs.typename()))?,
395 })
396 }
397
398 fn or(lhs, rhs) {
400 Ok(match (lhs, rhs) {
401 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
402 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
403 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
404 _ => Err(Error::TypeError("type implements BitOr", lhs.typename()))?,
405 })
406 }
407
408 fn xor(lhs, rhs) {
410 Ok(match (lhs, rhs) {
411 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
412 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
413 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
414 _ => Err(Error::TypeError("type implements BitXor", lhs.typename()))?,
415 })
416 }
417
418 fn neg(tail) {
420 Ok(match tail {
421 ConValue::Empty => ConValue::Empty,
422 ConValue::Int(v) => ConValue::Int(-v),
423 ConValue::Float(v) => ConValue::Float(-v),
424 _ => Err(Error::TypeError("type implements Neg", tail.typename()))?,
425 })
426 }
427
428 fn not(tail) {
430 Ok(match tail {
431 ConValue::Empty => ConValue::Empty,
432 ConValue::Int(v) => ConValue::Int(!v),
433 ConValue::Bool(v) => ConValue::Bool(!v),
434 _ => Err(Error::TypeError("type implements Not", tail.typename()))?,
435 })
436 }
437
438 fn cmp(head, tail) {
440 Ok(ConValue::Int(match (head, tail) {
441 (ConValue::Int(a), ConValue::Int(b)) => a.cmp(b) as _,
442 (ConValue::Bool(a), ConValue::Bool(b)) => a.cmp(b) as _,
443 (ConValue::Char(a), ConValue::Char(b)) => a.cmp(b) as _,
444 (ConValue::Str(a), ConValue::Str(b)) => a.cmp(b) as _,
445 (ConValue::Str(a), ConValue::String(b)) => a.to_ref().cmp(b.as_str()) as _,
446 (ConValue::String(a), ConValue::Str(b)) => a.as_str().cmp(b.to_ref()) as _,
447 (ConValue::String(a), ConValue::String(b)) => a.cmp(b) as _,
448 _ => Err(error_format!("Incomparable values: {head}, {tail}"))?
449 }))
450 }
451
452 fn deref(tail) @env {
454 Ok(tail.dereference_in(env)?.clone())
455 }
456];