kari/
builtins.rs

1use crate::{
2    context::{
3        self,
4        Context,
5    },
6    data::{
7        functions::{
8            Functions,
9            Scope,
10        },
11        types as t,
12        value::{
13            self,
14            Compute as _,
15            Value as _,
16        },
17    },
18    function::Function,
19};
20
21
22pub type Result  = std::result::Result<(), context::Error>;
23
24
25macro_rules! builtins {
26    ($($name:expr, $fn:ident, ($($arg:expr,)*);)*) => {
27        pub fn builtins<Host>(functions: &mut Functions<Function<Host>>) {
28            let scope = functions.root_scope();
29
30            functions
31                $(
32                    .define(
33                        scope,
34                        String::from($name),
35                        &[$(&$arg,)*],
36                        Function::Builtin($fn),
37                    )
38                    .expect("Failed to define builtin")
39                )*;
40        }
41    }
42}
43
44builtins!(
45    "print",   print,    (t::Any,);
46    "define",  define,   (t::List, t::Symbol,);
47    "define",  define_s, (t::List, t::Symbol, t::Scope,);
48    "caller",  caller,   ();
49    "fail",    fail,     ();
50    "eval",    eval,     (t::List,);
51    "load",    load,     (t::String,);
52    "to_list", to_list,  (t::Symbol,);
53
54    "drop",  drop,  (t::Any,);
55    "clone", clone, (t::Any,);
56    "swap",  swap,  (t::Any, t::Any,);
57    "dig",   dig,   (t::Any, t::List,);
58
59    "if", r#if, (t::List, t::List,);
60
61    "map",     map,     (t::List, t::List,);
62    "wrap",    wrap,    (t::Any,);
63    "unwrap",  unwrap,  (t::List,);
64    "prepend", prepend, (t::List, t::Any,);
65    "append",  append,  (t::List, t::Any,);
66
67    "+", add_n, (t::Number, t::Number,);
68    "*", mul_n, (t::Number, t::Number,);
69    "/", div_n, (t::Number, t::Number,);
70    ">", gt_n,  (t::Number, t::Number,);
71
72    "+", add_f, (t::Float, t::Float,);
73    "*", mul_f, (t::Float, t::Float,);
74    ">", gt_f,  (t::Float, t::Float,);
75
76    "=",   eq,  (t::Any, t::Any,);
77    "not", not, (t::Bool,);
78);
79
80
81fn print<Host>(
82    _:       &mut Host,
83    context: &mut dyn Context<Host>,
84    _:       Scope,
85)
86    -> Result
87{
88    let expression = context.stack().pop(&t::Any);
89    write!(context.output(), "{}", expression.kind)?;
90
91    Ok(())
92}
93
94fn define<Host>(
95    _:       &mut Host,
96    context: &mut dyn Context<Host>,
97    scope:   Scope,
98)
99    -> Result
100{
101    let (body, name) = context.stack()
102        .pop((&t::List, &t::Symbol));
103
104    context.functions().define(
105        scope,
106        name.inner,
107        &[],
108        Function::UserDefined { body },
109    )?;
110
111    Ok(())
112}
113
114fn define_s<Host>(
115    _:       &mut Host,
116    context: &mut dyn Context<Host>,
117    _:       Scope,
118)
119    -> Result
120{
121    let (body, name, scope) = context.stack()
122        .pop((&t::List, &t::Symbol, &t::Scope));
123
124    context.functions().define(
125        scope.inner,
126        name.inner,
127        &[],
128        Function::UserDefined { body },
129    )?;
130
131    Ok(())
132}
133
134fn caller<Host>(
135    _:       &mut Host,
136    context: &mut dyn Context<Host>,
137    _:       Scope,
138)
139    -> Result
140{
141    let caller = match context.call_stack().caller() {
142        Some(caller) => caller.clone(),
143        None         => return Err(context::Error::Caller),
144    };
145
146    context.stack().push(value::Scope::new(caller.scope, caller.span));
147
148    Ok(())
149}
150
151fn fail<Host>(
152    _: &mut Host,
153    _: &mut dyn Context<Host>,
154    _: Scope,
155)
156    -> Result
157{
158    Err(context::Error::Failure)
159}
160
161fn eval<Host>(
162    host:    &mut Host,
163    context: &mut dyn Context<Host>,
164    scope:   Scope,
165)
166    -> Result
167{
168    let list = context.stack().pop(&t::List);
169    let span = context.call_stack().operator().clone().span.merge(&list.span);
170
171    context.stack().create_substack();
172
173    context.evaluate_list(
174        host,
175        list,
176    )?;
177
178    let items = context.stack().destroy_substack();
179
180    let list = value::List::new(
181        value::ListInner::from_values(
182            items,
183            context.functions().new_scope(scope, "list"),
184        ),
185        span,
186    );
187    context.stack().push(list);
188
189    Ok(())
190}
191
192fn load<Host>(
193    _:       &mut Host,
194    context: &mut dyn Context<Host>,
195    scope:   Scope,
196)
197    -> Result
198{
199    let path = context.stack().pop(&t::String);
200
201    let list = context.load(path, scope)?;
202    context.stack().push(list);
203    Ok(())
204}
205
206fn to_list<Host>(
207    _:       &mut Host,
208    context: &mut dyn Context<Host>,
209    scope:   Scope,
210)
211    -> Result
212{
213    let symbol = context.stack().pop(&t::Symbol);
214
215    let (word, span) = symbol.open();
216    let list_span    = context.call_stack().operator().span.clone().merge(&span);
217    let word         = value::Any::new(value::Kind::Word(word), span);
218
219    let list = value::List::new(
220        value::ListInner::from_values(
221            vec![word],
222            context.functions().new_scope(scope, "list"),
223        ),
224        list_span,
225    );
226    context.stack().push(list);
227
228    Ok(())
229}
230
231
232fn drop<Host>(
233    _:       &mut Host,
234    context: &mut dyn Context<Host>,
235    _:       Scope,
236)
237    -> Result
238{
239    context.stack().pop(&t::Any);
240    Ok(())
241}
242
243fn clone<Host>(
244    _:       &mut Host,
245    context: &mut dyn Context<Host>,
246    _:       Scope,
247)
248    -> Result
249{
250    let mut expression = context.stack().pop(&t::Any);
251
252    expression.span = context.call_stack().operator().span.clone().merge(&expression.span);
253
254    context.stack().push((expression.clone(), expression));
255
256    Ok(())
257}
258
259fn swap<Host>(
260    _:       &mut Host,
261    context: &mut dyn Context<Host>,
262    _:       Scope,
263)
264    -> Result
265{
266    let (a, b) = context.stack().pop((&t::Any, &t::Any));
267    context.stack().push((b, a));
268
269    Ok(())
270}
271
272fn dig<Host>(
273    host:    &mut Host,
274    context: &mut dyn Context<Host>,
275    _:       Scope,
276)
277    -> Result
278{
279    let (item, f) = context.stack().pop((&t::Any, &t::List));
280    context.evaluate_list(host, f)?;
281    context.stack().push(item);
282    Ok(())
283}
284
285
286fn r#if<Host>(
287    host:    &mut Host,
288    context: &mut dyn Context<Host>,
289    _:       Scope,
290)
291    -> Result
292{
293    let (function, condition)  =context.stack()
294        .pop((&t::List, &t::List));
295
296    context.evaluate_list(host, condition)?;
297
298    let evaluated_condition = context.stack().pop(&t::Bool);
299
300    if evaluated_condition.inner {
301        context.evaluate_list(
302            host,
303            function,
304        )?;
305    }
306
307    Ok(())
308}
309
310
311fn map<Host>(
312    host:    &mut Host,
313    context: &mut dyn Context<Host>,
314    _:       Scope,
315)
316    -> Result
317{
318    let (list, function) = context.stack()
319        .pop((&t::List, &t::List));
320
321    context.stack().create_substack();
322
323    for item in list.inner.items {
324        context.stack().push(item);
325        context.evaluate_list(
326            host,
327            function.clone(),
328        )?;
329    }
330
331    let result = context.stack().destroy_substack();
332
333    let data = value::List::new(
334        value::ListInner::from_values(
335            result,
336            context.functions().new_scope(list.inner.scope, "list"),
337        ),
338        context.call_stack().operator().span.clone().merge(&list.span).merge(&function.span),
339    );
340    context.stack().push(data);
341
342    Ok(())
343}
344
345fn wrap<Host>(
346    _:       &mut Host,
347    context: &mut dyn Context<Host>,
348    scope:   Scope,
349)
350    -> Result
351{
352    let arg = context.stack().pop(&t::Any);
353
354    let span = context.call_stack().operator().span.clone().merge(&arg.span);
355    let list = value::List::new(
356        value::ListInner::from_values(
357            vec![arg],
358            context.functions().new_scope(scope, "list"),
359        ),
360        span,
361    );
362
363    context.stack().push(list);
364
365    Ok(())
366}
367
368fn unwrap<Host>(
369    _:       &mut Host,
370    context: &mut dyn Context<Host>,
371    _:       Scope,
372)
373    -> Result
374{
375    let list = context.stack().pop(&t::List);
376
377    for value in list.inner.items {
378        context.stack().push(value);
379    }
380
381    Ok(())
382}
383
384fn prepend<Host>(
385    _:       &mut Host,
386    context: &mut dyn Context<Host>,
387    _:       Scope,
388)
389    -> Result
390{
391    let (mut list, arg) = context.stack().pop((&t::List, &t::Any));
392
393    list.span = context.call_stack().operator().span.clone().merge(&list.span).merge(&arg.span);
394    list.inner.items.insert(0, arg);
395
396    context.stack().push(list);
397
398    Ok(())
399}
400
401fn append<Host>(
402    _:       &mut Host,
403    context: &mut dyn Context<Host>,
404    _:       Scope,
405)
406    -> Result
407{
408    let (mut list, arg) = context.stack().pop((&t::List, &t::Any));
409
410    list.span = context.call_stack().operator().span.clone().merge(&list.span).merge(&arg.span);
411    list.inner.items.push(arg);
412
413    context.stack().push(list);
414
415    Ok(())
416}
417
418
419fn add_n<Host>(
420    _:       &mut Host,
421    context: &mut dyn Context<Host>,
422    _:       Scope,
423)
424    -> Result
425{
426    let sum = context.stack()
427        .pop((&t::Number, &t::Number))
428        .compute::<value::Number, _, _>(|(a, b)| a + b);
429
430    context.stack().push(sum);
431
432    Ok(())
433}
434
435fn mul_n<Host>(
436    _:       &mut Host,
437    context: &mut dyn Context<Host>,
438    _:       Scope,
439)
440    -> Result
441{
442    let product = context.stack()
443        .pop((&t::Number, &t::Number))
444        .compute::<value::Number, _, _>(|(a, b)| a * b);
445
446    context.stack().push(product);
447
448    Ok(())
449}
450
451fn div_n<Host>(
452    _:       &mut Host,
453    context: &mut dyn Context<Host>,
454    _:       Scope,
455)
456    -> Result
457{
458    let quotient = context.stack()
459        .pop((&t::Number, &t::Number))
460        .compute::<value::Number, _, _>(|(a, b)| a / b);
461
462    context.stack().push(quotient);
463
464    Ok(())
465}
466
467fn gt_n<Host>(
468    _:       &mut Host,
469    context: &mut dyn Context<Host>,
470    _:       Scope,
471)
472    -> Result
473{
474    let is_greater = context.stack()
475        .pop((&t::Number, &t::Number))
476        .compute::<value::Bool, _, _>(|(a, b)| a > b);
477
478    context.stack().push(is_greater);
479
480    Ok(())
481}
482
483
484fn add_f<Host>(
485    _:       &mut Host,
486    context: &mut dyn Context<Host>,
487    _:       Scope,
488)
489    -> Result
490{
491    let sum = context.stack()
492        .pop((&t::Float, &t::Float))
493        .compute::<value::Float, _, _>(|(a, b)| a + b);
494
495    context.stack().push(sum);
496
497    Ok(())
498}
499
500fn mul_f<Host>(
501    _:       &mut Host,
502    context: &mut dyn Context<Host>,
503    _:       Scope,
504)
505    -> Result
506{
507    let product = context.stack()
508        .pop((&t::Float, &t::Float))
509        .compute::<value::Float, _, _>(|(a, b)| a * b);
510
511    context.stack().push(product);
512
513    Ok(())
514}
515
516fn gt_f<Host>(
517    _:       &mut Host,
518    context: &mut dyn Context<Host>,
519    _:       Scope,
520)
521    -> Result
522{
523    let is_greater = context.stack()
524        .pop((&t::Float, &t::Float))
525        .compute::<value::Bool, _, _>(|(a, b)| a > b);
526
527    context.stack().push(is_greater);
528
529    Ok(())
530}
531
532
533fn eq<Host>(
534    _:       &mut Host,
535    context: &mut dyn Context<Host>,
536    _:       Scope,
537)
538    -> Result
539{
540    let is_equal = context.stack()
541        .pop((&t::Any, &t::Any))
542        .compute::<value::Bool, _, _>(|(a, b)| a == b);
543
544    context.stack().push(is_equal);
545
546    Ok(())
547}
548
549fn not<Host>(
550    _:       &mut Host,
551    context: &mut dyn Context<Host>,
552    _:       Scope,
553)
554    -> Result
555{
556    let inverted = context.stack()
557        .pop(&t::Bool)
558        .compute::<value::Bool, _, _>(|b| !b);
559
560    context.stack().push(inverted);
561
562    Ok(())
563}