1use crate::{
2 interpreter::eval,
3 lisp,
4 model::{Env, HashMapRc, IntType, List, RuntimeError, Symbol, Value},
5 utils::{require_arg, require_typed_arg},
6};
7use cfg_if::cfg_if;
8use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc};
9cfg_if! {
10 if #[cfg(feature = "bigint")] {
11 use num_traits::ToPrimitive;
12 }
13}
14
15pub fn default_env() -> Env {
19 let mut env = Env::new();
20
21 env.define(
22 Symbol::from("print"),
23 Value::NativeFunc(|_env, args| {
24 let expr = require_arg("print", &args, 0)?;
25
26 println!("{}", &expr);
27 Ok(expr.clone())
28 }),
29 );
30
31 env.define(
32 Symbol::from("is_null"),
33 Value::NativeFunc(|_env, args| {
34 let val = require_arg("is_null", &args, 0)?;
35
36 Ok(Value::from(*val == Value::NIL))
37 }),
38 );
39
40 env.define(
41 Symbol::from("is_number"),
42 Value::NativeFunc(|_env, args| {
43 let val = require_arg("is_number", &args, 0)?;
44
45 Ok(match val {
46 Value::Int(_) => Value::True,
47 Value::Float(_) => Value::True,
48 _ => Value::NIL,
49 })
50 }),
51 );
52
53 env.define(
54 Symbol::from("is_symbol"),
55 Value::NativeFunc(|_env, args| {
56 let val = require_arg("is_symbol", &args, 0)?;
57
58 Ok(match val {
59 Value::Symbol(_) => Value::True,
60 _ => Value::NIL,
61 })
62 }),
63 );
64
65 env.define(
66 Symbol::from("is_boolean"),
67 Value::NativeFunc(|_env, args| {
68 let val = require_arg("is_boolean", &args, 0)?;
69
70 Ok(match val {
71 Value::True => Value::True,
72 Value::False => Value::True,
73 _ => Value::NIL,
74 })
75 }),
76 );
77
78 env.define(
79 Symbol::from("is_procedure"),
80 Value::NativeFunc(|_env, args| {
81 let val = require_arg("is_procedure", &args, 0)?;
82
83 Ok(match val {
84 Value::Lambda(_) => Value::True,
85 Value::NativeFunc(_) => Value::True,
86 _ => Value::NIL,
87 })
88 }),
89 );
90
91 env.define(
92 Symbol::from("is_pair"),
93 Value::NativeFunc(|_env, args| {
94 let val = require_arg("is_pair", &args, 0)?;
95
96 Ok(match val {
97 Value::List(_) => Value::True,
98 _ => Value::NIL,
99 })
100 }),
101 );
102
103 env.define(
104 Symbol::from("car"),
105 Value::NativeFunc(|_env, args| {
106 let list = require_typed_arg::<&List>("car", &args, 0)?;
107
108 list.car()
109 }),
110 );
111
112 env.define(
113 Symbol::from("cdr"),
114 Value::NativeFunc(|_env, args| {
115 let list = require_typed_arg::<&List>("cdr", &args, 0)?;
116
117 Ok(Value::List(list.cdr()))
118 }),
119 );
120
121 env.define(
122 Symbol::from("cons"),
123 Value::NativeFunc(|_env, args| {
124 let car = require_arg("cons", &args, 0)?;
125 let cdr = require_typed_arg::<&List>("cons", &args, 1)?;
126
127 Ok(Value::List(cdr.cons(car.clone())))
128 }),
129 );
130
131 env.define(
132 Symbol::from("list"),
133 Value::NativeFunc(|_env, args| Ok(Value::List(args.iter().collect::<List>()))),
134 );
135
136 env.define(
137 Symbol::from("nth"),
138 Value::NativeFunc(|_env, args| {
139 let index = require_typed_arg::<IntType>("nth", &args, 0)?;
140 let list = require_typed_arg::<&List>("nth", &args, 1)?;
141
142 let index = TryInto::<usize>::try_into(index).map_err(|_| RuntimeError {
143 msg: "Failed converting to `usize`".to_owned(),
144 })?;
145
146 Ok(list.into_iter().nth(index).unwrap_or(Value::NIL))
147 }),
148 );
149
150 env.define(
151 Symbol::from("sort"),
152 Value::NativeFunc(|_env, args| {
153 let list = require_typed_arg::<&List>("sort", &args, 0)?;
154
155 let mut v: Vec<Value> = list.into_iter().collect();
156
157 v.sort();
158
159 Ok(Value::List(v.into_iter().collect()))
160 }),
161 );
162
163 env.define(
164 Symbol::from("reverse"),
165 Value::NativeFunc(|_env, args| {
166 let list = require_typed_arg::<&List>("reverse", &args, 0)?;
167
168 let mut v: Vec<Value> = list.into_iter().collect();
169
170 v.reverse();
171
172 Ok(Value::List(v.into_iter().collect()))
173 }),
174 );
175
176 env.define(
177 Symbol::from("map"),
178 Value::NativeFunc(|env, args| {
179 let func = require_arg("map", &args, 0)?;
180 let list = require_typed_arg::<&List>("map", &args, 1)?;
181
182 list.into_iter()
183 .map(|val| {
184 let expr = lisp! { ({func.clone()} (quote {val})) };
185
186 eval(env.clone(), &expr)
187 })
188 .collect::<Result<List, RuntimeError>>()
189 .map(Value::List)
190 }),
191 );
192
193 env.define(
195 Symbol::from("filter"),
196 Value::NativeFunc(|env, args| {
197 let func = require_arg("filter", &args, 0)?;
198 let list = require_typed_arg::<&List>("filter", &args, 1)?;
199
200 list.into_iter()
201 .filter_map(|val: Value| -> Option<Result<Value, RuntimeError>> {
202 let expr = lisp! { ({func.clone()} (quote {val.clone()})) };
203
204 match eval(env.clone(), &expr) {
205 Ok(matches) => {
206 if matches.into() {
207 Some(Ok(val))
208 } else {
209 None
210 }
211 }
212 Err(e) => Some(Err(e)),
213 }
214 })
215 .collect::<Result<List, RuntimeError>>()
216 .map(Value::List)
217 }),
218 );
219
220 env.define(
221 Symbol::from("length"),
222 Value::NativeFunc(|_env, args| {
223 let list = require_typed_arg::<&List>("length", &args, 0)?;
224
225 cfg_if! {
226 if #[cfg(feature = "bigint")] {
227 Ok(Value::Int(list.into_iter().len().into()))
228 } else {
229 Ok(Value::Int(list.into_iter().len() as IntType))
230 }
231 }
232 }),
233 );
234
235 env.define(
236 Symbol::from("range"),
237 Value::NativeFunc(|_env, args| {
238 let start = require_typed_arg::<IntType>("range", &args, 0)?;
239 let end = require_typed_arg::<IntType>("range", &args, 1)?;
240
241 let mut current = start;
242
243 Ok(Value::List(
244 std::iter::from_fn(move || {
245 if current == end {
246 None
247 } else {
248 let res = Some(current.clone());
249
250 current += 1;
251
252 res
253 }
254 })
255 .map(Value::from)
256 .collect(),
257 ))
258 }),
259 );
260
261 env.define(
262 Symbol::from("hash"),
263 Value::NativeFunc(|_env, args| {
264 let chunks = args.chunks(2);
265
266 let mut hash = HashMap::new();
267
268 for pair in chunks {
269 let key = pair.get(0).unwrap();
270 let value = pair.get(1);
271
272 if let Some(value) = value {
273 hash.insert(key.clone(), value.clone());
274 } else {
275 return Err(RuntimeError {
276 msg: format!("Must pass an even number of arguments to 'hash', because they're used as key/value pairs; found extra argument {}", key)
277 });
278 }
279 }
280
281 Ok(Value::HashMap(Rc::new(RefCell::new(hash))))
282 }),
283 );
284
285 env.define(
286 Symbol::from("hash_get"),
287 Value::NativeFunc(|_env, args| {
288 let hash = require_typed_arg::<&HashMapRc>("hash_get", &args, 0)?;
289 let key = require_arg("hash_get", &args, 1)?;
290
291 Ok(hash
292 .borrow()
293 .get(key)
294 .map(|v| v.clone())
295 .unwrap_or(Value::NIL))
296 }),
297 );
298
299 env.define(
300 Symbol::from("hash_set"),
301 Value::NativeFunc(|_env, args| {
302 let hash = require_typed_arg::<&HashMapRc>("hash_set", &args, 0)?;
303 let key = require_arg("hash_set", &args, 1)?;
304 let value = require_arg("hash_set", &args, 2)?;
305
306 hash.borrow_mut().insert(key.clone(), value.clone());
307
308 Ok(Value::HashMap(hash.clone()))
309 }),
310 );
311
312 env.define(
313 Symbol::from("+"),
314 Value::NativeFunc(|_env, args| {
315 let first_arg = require_arg("+", &args, 1)?;
316
317 let mut total = match first_arg {
318 Value::Int(_) => Ok(Value::Int(0.into())),
319 Value::Float(_) => Ok(Value::Float(0.0)),
320 Value::String(_) => Ok(Value::String("".into())),
321 _ => Err(RuntimeError {
322 msg: format!(
323 "Function \"+\" requires arguments to be numbers or strings; found {}",
324 first_arg
325 ),
326 }),
327 }?;
328
329 for arg in args {
330 total = (&total + &arg).map_err(|_| RuntimeError {
331 msg: format!(
332 "Function \"+\" requires arguments to be numbers or strings; found {}",
333 arg
334 ),
335 })?;
336 }
337
338 Ok(total)
339 }),
340 );
341
342 env.define(
343 Symbol::from("-"),
344 Value::NativeFunc(|_env, args| {
345 let a = require_arg("-", &args, 0)?;
346 let b = require_arg("-", &args, 1)?;
347
348 (a - b).map_err(|_| RuntimeError {
349 msg: String::from("Function \"-\" requires arguments to be numbers"),
350 })
351 }),
352 );
353
354 env.define(
355 Symbol::from("*"),
356 Value::NativeFunc(|_env, args| {
357 let mut product = Value::Int(1.into());
358
359 for arg in args {
360 product = (&product * &arg).map_err(|_| RuntimeError {
361 msg: format!(
362 "Function \"*\" requires arguments to be numbers; found {}",
363 arg
364 ),
365 })?;
366 }
367
368 Ok(product)
369 }),
370 );
371
372 env.define(
373 Symbol::from("/"),
374 Value::NativeFunc(|_env, args| {
375 let a = require_arg("/", &args, 0)?;
376 let b = require_arg("/", &args, 1)?;
377
378 (a / b).map_err(|_| RuntimeError {
379 msg: String::from("Function \"/\" requires arguments to be numbers"),
380 })
381 }),
382 );
383
384 env.define(
385 Symbol::from("truncate"),
386 Value::NativeFunc(|_env, args| {
387 let a = require_arg("truncate", &args, 0)?;
388 let b = require_arg("truncate", &args, 1)?;
389
390 if let (Ok(a), Ok(b)) = (
391 TryInto::<IntType>::try_into(a),
392 TryInto::<IntType>::try_into(b),
393 ) {
394 return Ok(Value::Int(a / b));
395 }
396
397 Err(RuntimeError {
398 msg: String::from("Function \"truncate\" requires arguments to be integers"),
399 })
400 }),
401 );
402
403 env.define(
404 Symbol::from("not"),
405 Value::NativeFunc(|_env, args| {
406 let a = require_arg("not", &args, 0)?;
407 let a: bool = a.into();
408
409 Ok(Value::from(!a))
410 }),
411 );
412
413 env.define(
414 Symbol::from("=="),
415 Value::NativeFunc(|_env, args| {
416 let a = require_arg("==", &args, 0)?;
417 let b = require_arg("==", &args, 1)?;
418
419 Ok(Value::from(a == b))
420 }),
421 );
422
423 env.define(
424 Symbol::from("!="),
425 Value::NativeFunc(|_env, args| {
426 let a = require_arg("!=", &args, 0)?;
427 let b = require_arg("!=", &args, 1)?;
428
429 Ok(Value::from(a != b))
430 }),
431 );
432
433 env.define(
434 Symbol::from("<"),
435 Value::NativeFunc(|_env, args| {
436 let a = require_arg("<", &args, 0)?;
437 let b = require_arg("<", &args, 1)?;
438
439 Ok(Value::from(a < b))
440 }),
441 );
442
443 env.define(
444 Symbol::from("<="),
445 Value::NativeFunc(|_env, args| {
446 let a = require_arg("<=", &args, 0)?;
447 let b = require_arg("<=", &args, 1)?;
448
449 Ok(Value::from(a <= b))
450 }),
451 );
452
453 env.define(
454 Symbol::from(">"),
455 Value::NativeFunc(|_env, args| {
456 let a = require_arg(">", &args, 0)?;
457 let b = require_arg(">", &args, 1)?;
458
459 Ok(Value::from(a > b))
460 }),
461 );
462
463 env.define(
464 Symbol::from(">="),
465 Value::NativeFunc(|_env, args| {
466 let a = require_arg(">=", &args, 0)?;
467 let b = require_arg(">=", &args, 1)?;
468
469 Ok(Value::from(a >= b))
470 }),
471 );
472
473 env.define(
474 Symbol::from("eval"),
475 Value::NativeFunc(|env, args| {
476 let expr = require_arg("eval", &args, 0)?;
477
478 eval(env, expr)
479 }),
480 );
481
482 env.define(
483 Symbol::from("apply"),
484 Value::NativeFunc(|env, args| {
485 let func = require_arg("apply", &args, 0)?;
486 let params = require_typed_arg::<&List>("apply", &args, 1)?;
487
488 eval(env, &Value::List(params.cons(func.clone())))
489 }),
490 );
491
492 env
493}