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 super::Callable for Builtin {
45 fn call(&self, interpreter: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
46 (self.func)(interpreter, args)
47 }
48
49 fn name(&self) -> cl_ast::Sym {
50 self.name.into()
51 }
52}
53
54pub macro builtin(
72 $(#[$($meta:tt)*])*
73 fn $name:ident ($($arg:pat),*$(,)?) $(@$env:tt)? $body:block
74) {{
75 $(#[$($meta)*])*
76 fn $name(_env: &mut Environment, _args: &[ConValue]) -> IResult<ConValue> {
77 $(#[allow(unused)]let $env = _env;)?
79 #[allow(clippy::redundant_at_rest_pattern, irrefutable_let_patterns)]
81 let [$($arg),*] = _args else {
82 Err($crate::error::Error::TypeError())?
83 };
84 $body.map(Into::into)
85 }
86 Builtin {
87 name: stringify!($name),
88 desc: stringify![builtin fn $name($($arg),*)],
89 func: &$name,
90 }
91}}
92
93pub macro builtins($(
95 $(#[$($meta:tt)*])*
96 fn $name:ident ($($args:tt)*) $(@$env:tt)? $body:block
97)*) {
98 [$(builtin!($(#[$($meta)*])* fn $name ($($args)*) $(@$env)? $body)),*]
99}
100
101pub macro error_format ($($t:tt)*) {
104 $crate::error::Error::BuiltinError(format!($($t)*))
105}
106
107pub const Builtins: &[Builtin] = &builtins![
108 fn fmt(args @ ..) {
110 use std::fmt::Write;
111 let mut out = String::new();
112 if let Err(e) = args.iter().try_for_each(|arg| write!(out, "{arg}")) {
113 eprintln!("{e}");
114 }
115 Ok(out)
116 }
117
118 fn print(args @ ..) {
120 let mut out = stdout().lock();
121 args.iter().try_for_each(|arg| write!(out, "{arg}") ).ok();
122 Ok(())
123 }
124
125 fn println(args @ ..) {
127 let mut out = stdout().lock();
128 args.iter().try_for_each(|arg| write!(out, "{arg}") ).ok();
129 writeln!(out).ok();
130 Ok(())
131 }
132
133 fn dbg(arg) {
135 println!("{arg:?}");
136 Ok(arg.clone())
137 }
138
139 fn dbgp(args @ ..) {
141 let mut out = stdout().lock();
142 args.iter().try_for_each(|arg| writeln!(out, "{arg:#?}") ).ok();
143 Ok(())
144 }
145
146 fn panic(message) {
147 Err(error_format!("Panic: {message}"))?;
148 Ok(())
149 }
150
151 fn dump() @env {
153 println!("{env}");
154 Ok(())
155 }
156
157 fn builtins() @env {
158 for builtin in env.globals().values().flatten().filter(|v| matches!(v, ConValue::Builtin(_))) {
159 println!("{builtin}")
160 }
161 Ok(())
162 }
163
164 fn len(list) @env {
166 Ok(match list {
167 ConValue::Empty => 0,
168 ConValue::String(s) => s.chars().count() as _,
169 ConValue::Ref(r) => {
170 return len(env, &[env.get_id(*r).ok_or(Error::StackOverflow(*r))?.clone()])
171 }
172 ConValue::Array(t) => t.len() as _,
173 ConValue::Tuple(t) => t.len() as _,
174 _ => Err(Error::TypeError())?,
175 })
176 }
177
178 fn chars(string) @env {
179 Ok(match string {
180 ConValue::String(s) => ConValue::Array(s.chars().map(Into::into).collect()),
181 ConValue::Ref(r) => {
182 return chars(env, &[env.get_id(*r).ok_or(Error::StackOverflow(*r))?.clone()])
183 }
184 _ => Err(Error::TypeError())?,
185 })
186 }
187
188 fn dump_symbols() {
189 println!("{}", cl_structures::intern::string_interner::StringInterner::global());
190 Ok(ConValue::Empty)
191 }
192
193 fn slice_of(ConValue::Ref(arr), ConValue::Int(start)) {
194 Ok(ConValue::Slice(*arr, *start as usize))
195 }
196
197 fn shark() {
199 Ok('\u{1f988}')
200 }
201];
202
203pub const Math: &[Builtin] = &builtins![
204 fn mul(lhs, rhs) {
206 Ok(match (lhs, rhs) {
207 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
208 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a * b),
209 _ => Err(Error::TypeError())?
210 })
211 }
212
213 fn div(lhs, rhs) {
215 Ok(match (lhs, rhs){
216 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
217 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a / b),
218 _ => Err(Error::TypeError())?
219 })
220 }
221
222 fn rem(lhs, rhs) {
224 Ok(match (lhs, rhs) {
225 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
226 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a % b),
227 _ => Err(Error::TypeError())?,
228 })
229 }
230
231 fn add(lhs, rhs) {
233 Ok(match (lhs, rhs) {
234 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
235 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b),
236 (ConValue::String(a), ConValue::String(b)) => (a.to_string() + &b.to_string()).into(),
237 _ => Err(Error::TypeError())?
238 })
239 }
240
241 fn sub(lhs, rhs) {
243 Ok(match (lhs, rhs) {
244 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
245 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a - b),
246 _ => Err(Error::TypeError())?,
247 })
248 }
249
250 fn shl(lhs, rhs) {
252 Ok(match (lhs, rhs) {
253 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
254 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a << b),
255 _ => Err(Error::TypeError())?,
256 })
257 }
258
259 fn shr(lhs, rhs) {
261 Ok(match (lhs, rhs) {
262 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
263 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a >> b),
264 _ => Err(Error::TypeError())?,
265 })
266 }
267
268 fn and(lhs, rhs) {
270 Ok(match (lhs, rhs) {
271 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
272 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
273 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
274 _ => Err(Error::TypeError())?,
275 })
276 }
277
278 fn or(lhs, rhs) {
280 Ok(match (lhs, rhs) {
281 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
282 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
283 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
284 _ => Err(Error::TypeError())?,
285 })
286 }
287
288 fn xor(lhs, rhs) {
290 Ok(match (lhs, rhs) {
291 (ConValue::Empty, ConValue::Empty) => ConValue::Empty,
292 (ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
293 (ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
294 _ => Err(Error::TypeError())?,
295 })
296 }
297
298 #[allow(non_snake_case)]
299 fn RangeExc(start, end) {
300 Ok(ConValue::TupleStruct(Box::new((
301 "RangeExc", Box::new([start.clone(), end.clone()])
302 ))))
303 }
304
305 #[allow(non_snake_case)]
306 fn RangeInc(start, end) {
307 Ok(ConValue::TupleStruct(Box::new((
308 "RangeInc", Box::new([start.clone(), end.clone()])
309 ))))
310 }
311
312 #[allow(non_snake_case)]
313 fn RangeTo(end) {
314 Ok(ConValue::TupleStruct(Box::new((
315 "RangeInc", Box::new([end.clone()])
316 ))))
317 }
318
319 fn neg(tail) {
321 Ok(match tail {
322 ConValue::Empty => ConValue::Empty,
323 ConValue::Int(v) => ConValue::Int(v.wrapping_neg()),
324 ConValue::Float(v) => ConValue::Float(-v),
325 _ => Err(Error::TypeError())?,
326 })
327 }
328
329 fn not(tail) {
331 Ok(match tail {
332 ConValue::Empty => ConValue::Empty,
333 ConValue::Int(v) => ConValue::Int(!v),
334 ConValue::Bool(v) => ConValue::Bool(!v),
335 _ => Err(Error::TypeError())?,
336 })
337 }
338
339 fn cmp(head, tail) {
341 Ok(ConValue::Int(match (head, tail) {
342 (ConValue::Int(a), ConValue::Int(b)) => a.cmp(b) as _,
343 (ConValue::Bool(a), ConValue::Bool(b)) => a.cmp(b) as _,
344 (ConValue::Char(a), ConValue::Char(b)) => a.cmp(b) as _,
345 (ConValue::String(a), ConValue::String(b)) => a.cmp(b) as _,
346 _ => Err(error_format!("Incomparable values: {head}, {tail}"))?
347 }))
348 }
349
350 fn deref(tail) @env {
352 Ok(match tail {
353 ConValue::Ref(v) => env.get_id(*v).cloned().ok_or(Error::StackOverflow(*v))?,
354 _ => tail.clone(),
355 })
356 }
357];