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