1#![allow(non_upper_case_globals)]
2
3use crate::{
4 convalue::ConValue,
5 env::Environment,
6 error::{Error, IResult},
7};
8use std::io::{Write, stdout};
9
10#[derive(Clone, Copy)]
12pub struct Builtin {
13 pub name: &'static str,
15 pub desc: &'static str,
17 pub func: &'static dyn Fn(&mut Environment, &[ConValue]) -> IResult<ConValue>,
19}
20
21impl Builtin {
22 pub const fn new(
24 name: &'static str,
25 desc: &'static str,
26 func: &'static impl Fn(&mut Environment, &[ConValue]) -> IResult<ConValue>,
27 ) -> Builtin {
28 Builtin { name, desc, func }
29 }
30
31 pub const fn description(&self) -> &'static str {
32 self.desc
33 }
34}
35
36impl std::fmt::Debug for Builtin {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 f.debug_struct("Builtin")
39 .field("description", &self.desc)
40 .finish_non_exhaustive()
41 }
42}
43
44impl std::fmt::Display for Builtin {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 f.write_str(self.desc)
47 }
48}
49
50impl super::Callable for Builtin {
51 fn call(&self, interpreter: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
52 (self.func)(interpreter, args)
53 }
54
55 fn name(&self) -> cl_ast::Sym {
56 self.name.into()
57 }
58}
59
60pub macro builtin(
78 $(#[$($meta:tt)*])*
79 fn $name:ident ($($arg:pat),*$(,)?) $(@$env:tt)? $body:block
80) {{
81 $(#[$($meta)*])*
82 fn $name(_env: &mut Environment, _args: &[ConValue]) -> IResult<ConValue> {
83 $(#[allow(unused)]let $env = _env;)?
85 #[allow(clippy::redundant_at_rest_pattern, irrefutable_let_patterns)]
87 let [$($arg),*] = _args else {
88 Err($crate::error::Error::TypeError())?
89 };
90 $body.map(Into::into)
91 }
92 Builtin {
93 name: stringify!($name),
94 desc: stringify![builtin fn $name($($arg),*)],
95 func: &$name,
96 }
97}}
98
99pub macro builtins($(
101 $(#[$($meta:tt)*])*
102 fn $name:ident ($($args:tt)*) $(@$env:tt)? $body:block
103)*) {
104 [$(builtin!($(#[$($meta)*])* fn $name ($($args)*) $(@$env)? $body)),*]
105}
106
107pub macro error_format ($($t:tt)*) {
110 $crate::error::Error::BuiltinError(format!($($t)*))
111}
112
113pub const Builtins: &[Builtin] = &builtins![
114 fn fmt(args @ ..) {
116 use std::fmt::Write;
117 let mut out = String::new();
118 if let Err(e) = args.iter().try_for_each(|arg| write!(out, "{arg}")) {
119 eprintln!("{e}");
120 }
121 Ok(out)
122 }
123
124 fn print(args @ ..) {
126 let mut out = stdout().lock();
127 args.iter().try_for_each(|arg| write!(out, "{arg}") ).ok();
128 Ok(())
129 }
130
131 fn println(args @ ..) {
133 let mut out = stdout().lock();
134 args.iter().try_for_each(|arg| write!(out, "{arg}") ).ok();
135 writeln!(out).ok();
136 Ok(())
137 }
138
139 fn dbg(arg) {
141 println!("{arg:?}");
142 Ok(arg.clone())
143 }
144
145 fn dbgp(args @ ..) {
147 let mut out = stdout().lock();
148 args.iter().try_for_each(|arg| writeln!(out, "{arg:#?}") ).ok();
149 Ok(())
150 }
151
152 fn panic(args @ ..) @env {
153 use std::fmt::Write;
154 let mut out = String::new();
155 if let Err(e) = args.iter().try_for_each(|arg| write!(out, "{arg}")) {
156 println!("{e}");
157 }
158 let mut stdout = stdout().lock();
159 write!(stdout, "Explicit panic: `").ok();
160 args.iter().try_for_each(|arg| write!(stdout, "{arg}") ).ok();
161 writeln!(stdout, "`").ok();
162 Err(Error::Panic(out))?;
163 Ok(())
164 }
165
166 fn dump() @env {
168 println!("{env}");
169 Ok(())
170 }
171
172 fn globals() @env {
174 let globals = env.globals();
175 Ok(ConValue::Slice(globals.base, globals.binds.len()))
176 }
177
178 fn builtins() @env {
179 let len = env.globals().binds.len();
180 for builtin in 0..len {
181 if let Some(value @ ConValue::Builtin(_)) = env.get_id(builtin) {
182 println!("{builtin}: {value}")
183 }
184 }
185 Ok(())
186 }
187
188 fn alloca(ConValue::Int(len)) @env {
189 Ok(env.alloca(ConValue::Empty, *len as usize))
190 }
191
192 fn len(list) @env {
194 Ok(match list {
195 ConValue::Empty => 0,
196 ConValue::Str(s) => s.chars().count() as _,
197 ConValue::String(s) => s.chars().count() as _,
198 ConValue::Ref(r) => {
199 return len(env, &[env.get_id(*r).ok_or(Error::StackOverflow(*r))?.clone()])
200 }
201 ConValue::Slice(_, len) => *len as _,
202 ConValue::Array(arr) => arr.len() as _,
203 ConValue::Tuple(t) => t.len() as _,
204 _ => Err(Error::TypeError())?,
205 })
206 }
207
208 fn push(ConValue::Ref(index), item) @env{
209 let Some(ConValue::Array(v)) = env.get_id_mut(*index) else {
210 Err(Error::TypeError())?
211 };
212
213 let mut items = std::mem::take(v).into_vec();
214 items.push(item.clone());
215 *v = items.into_boxed_slice();
216
217 Ok(ConValue::Empty)
218 }
219
220 fn chars(string) @env {
221 Ok(match string {
222 ConValue::Str(s) => ConValue::Array(s.chars().map(Into::into).collect()),
223 ConValue::String(s) => ConValue::Array(s.chars().map(Into::into).collect()),
224 ConValue::Ref(r) => {
225 return chars(env, &[env.get_id(*r).ok_or(Error::StackOverflow(*r))?.clone()])
226 }
227 _ => Err(Error::TypeError())?,
228 })
229 }
230
231 fn dump_symbols() {
232 println!("{}", cl_structures::intern::string_interner::StringInterner::global());
233 Ok(ConValue::Empty)
234 }
235
236 fn slice_of(ConValue::Ref(arr), ConValue::Int(start)) {
237 Ok(ConValue::Slice(*arr, *start as usize))
238 }
239
240 fn shark() {
242 Ok('\u{1f988}')
243 }
244];
245
246pub const Math: &[Builtin] = &builtins![
247 fn mul(lhs, rhs) {
249 Ok(match (lhs, rhs) {
250 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
251 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a * b),
252 _ => Err(Error::TypeError())?
253 })
254 }
255
256 fn div(lhs, rhs) {
258 Ok(match (lhs, rhs){
259 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
260 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a / b),
261 _ => Err(Error::TypeError())?
262 })
263 }
264
265 fn rem(lhs, rhs) {
267 Ok(match (lhs, rhs) {
268 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
269 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a % b),
270 _ => Err(Error::TypeError())?,
271 })
272 }
273
274 fn add(lhs, rhs) {
276 Ok(match (lhs, rhs) {
277 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
278 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b),
279 (ConValue::Str(a), ConValue::Str(b)) => (a.to_string() + b).into(),
280 (ConValue::Str(a), ConValue::String(b)) => (a.to_string() + b).into(),
281 (ConValue::String(a), ConValue::Str(b)) => (a.to_string() + b).into(),
282 (ConValue::String(a), ConValue::String(b)) => (a.to_string() + b).into(),
283 (ConValue::Str(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(*c); s.into() }
284 (ConValue::String(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(*c); s.into() }
285 (ConValue::Char(a), ConValue::Char(b)) => {
286 ConValue::String([a, b].into_iter().collect::<String>())
287 }
288 _ => Err(Error::TypeError())?
289 })
290 }
291
292 fn sub(lhs, rhs) {
294 Ok(match (lhs, rhs) {
295 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
296 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a - b),
297 _ => Err(Error::TypeError())?,
298 })
299 }
300
301 fn shl(lhs, rhs) {
303 Ok(match (lhs, rhs) {
304 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
305 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a << b),
306 _ => Err(Error::TypeError())?,
307 })
308 }
309
310 fn shr(lhs, rhs) {
312 Ok(match (lhs, rhs) {
313 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
314 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a >> b),
315 _ => Err(Error::TypeError())?,
316 })
317 }
318
319 fn and(lhs, rhs) {
321 Ok(match (lhs, rhs) {
322 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
323 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
324 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
325 _ => Err(Error::TypeError())?,
326 })
327 }
328
329 fn or(lhs, rhs) {
331 Ok(match (lhs, rhs) {
332 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
333 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
334 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
335 _ => Err(Error::TypeError())?,
336 })
337 }
338
339 fn xor(lhs, rhs) {
341 Ok(match (lhs, rhs) {
342 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
343 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
344 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
345 _ => Err(Error::TypeError())?,
346 })
347 }
348
349 #[allow(non_snake_case)]
350 fn RangeExc(start, end) @env {
351 Ok(ConValue::TupleStruct("RangeExc".into(), Box::new(Box::new([start.clone(), end.clone()]))))
352 }
353
354 #[allow(non_snake_case)]
355 fn RangeInc(start, end) @env {
356 Ok(ConValue::TupleStruct("RangeInc".into(), Box::new(Box::new([start.clone(), end.clone()]))))
357 }
358
359 #[allow(non_snake_case)]
360 fn RangeTo(end) @env {
361 Ok(ConValue::TupleStruct("RangeTo".into(), Box::new(Box::new([end.clone()]))))
362 }
363
364 #[allow(non_snake_case)]
365 fn RangeToInc(end) @env {
366 Ok(ConValue::TupleStruct("RangeToInc".into(), Box::new(Box::new([end.clone()]))))
367 }
368
369 fn neg(tail) {
371 Ok(match tail {
372 ConValue::Empty => ConValue::Empty,
373 ConValue::Int(v) => ConValue::Int(v.wrapping_neg()),
374 ConValue::Float(v) => ConValue::Float(-v),
375 _ => Err(Error::TypeError())?,
376 })
377 }
378
379 fn not(tail) {
381 Ok(match tail {
382 ConValue::Empty => ConValue::Empty,
383 ConValue::Int(v) => ConValue::Int(!v),
384 ConValue::Bool(v) => ConValue::Bool(!v),
385 _ => Err(Error::TypeError())?,
386 })
387 }
388
389 fn cmp(head, tail) {
391 Ok(ConValue::Int(match (head, tail) {
392 (ConValue::Int(a), ConValue::Int(b)) => a.cmp(b) as _,
393 (ConValue::Bool(a), ConValue::Bool(b)) => a.cmp(b) as _,
394 (ConValue::Char(a), ConValue::Char(b)) => a.cmp(b) as _,
395 (ConValue::Str(a), ConValue::Str(b)) => a.cmp(b) as _,
396 (ConValue::Str(a), ConValue::String(b)) => a.to_ref().cmp(b.as_str()) as _,
397 (ConValue::String(a), ConValue::Str(b)) => a.as_str().cmp(b.to_ref()) as _,
398 (ConValue::String(a), ConValue::String(b)) => a.cmp(b) as _,
399 _ => Err(error_format!("Incomparable values: {head}, {tail}"))?
400 }))
401 }
402
403 fn deref(tail) @env {
405 Ok(match tail {
406 ConValue::Ref(v) => env.get_id(*v).cloned().ok_or(Error::StackOverflow(*v))?,
407 _ => tail.clone(),
408 })
409 }
410];