1use crate::compat::Rc;
2use crate::interpreter::Interpreter;
3use crate::value::Value;
4
5use crate::primitives::{
6 abs_builtin,
8 add_builtin,
10 bit_and_builtin,
12 bit_not_builtin,
13 bit_or_builtin,
14 bit_xor_builtin,
15 cons_builtin,
17 construct_record_builtin,
18 def_builtin,
20 div_builtin,
21 doc_builtin,
22 drop_builtin,
24 eq_builtin,
25 floor_div_builtin,
26 from_r_builtin,
27 get_record_field_builtin,
28 greater_equal_builtin,
29 greater_than_builtin,
30 head_builtin,
31 help_builtin,
32 is_record_type_builtin,
33 less_equal_builtin,
34 less_than_builtin,
36 list_builtin,
37 list_to_vector_builtin,
38 make_record_type_builtin,
39 make_vector_builtin,
40 max_builtin,
41 min_builtin,
42 mod_builtin,
43 mul_builtin,
44 not_equal_builtin,
45 null_predicate_builtin,
46 pick_builtin,
47 print_builtin,
50 words_builtin,
51 clear_builtin,
53 stack_builtin,
54 r_fetch_builtin,
55 record_type_of_builtin,
56 roll_builtin,
57 set_record_field_builtin,
58 shl_builtin,
60 shr_builtin,
61 sub_builtin,
62 tail_builtin,
63 to_r_builtin,
65 to_string_builtin,
67 trunc_div_builtin,
68 truthy_predicate_builtin,
70 type_of_builtin,
72 val_builtin,
73 vector_builtin,
74 vector_length_builtin,
75 vector_ref_builtin,
76 vector_set_builtin,
77 vector_to_list_builtin,
78};
79
80#[cfg(feature = "advanced_math")]
82use crate::primitives::{
83 ceil_builtin,
84 cos_builtin,
85 exp_builtin,
86 floor_builtin,
87 log_builtin,
88 pow_builtin,
89 round_builtin,
90 sin_builtin,
91 sqrt_builtin,
92 tan_builtin,
93};
94
95#[cfg(feature = "datetime")]
97use crate::primitives::{
98 date_add_builtin, date_equal_builtin, date_greater_than_builtin, date_less_than_builtin,
99 date_sub_builtin, datetime_builtin, datetime_to_string_builtin,
100 datetime_with_offset_builtin, day_builtin, duration_builtin, duration_equal_builtin,
101 duration_greater_than_builtin, duration_less_than_builtin, duration_to_seconds_builtin,
102 hour_builtin, minute_builtin, month_builtin, now_builtin, second_builtin,
103 string_to_datetime_builtin, timestamp_builtin, timestamp_to_datetime_builtin,
104 to_local_builtin, to_utc_builtin, weekday_builtin, year_builtin,
105};
106
107use crate::primitives::{
109 i16_avg_builtin, i16_buffer_builtin, i16_length_builtin, i16_max_builtin, i16_min_builtin,
110 i16_pop_builtin, i16_push_builtin, i16_ref_builtin, i16_set_builtin,
111};
112
113pub fn register_builtins(interp: &mut Interpreter) {
115 use crate::interpreter::DictEntry;
116
117 let add_atom = interp.intern_atom("+");
119 interp.dictionary.insert(
120 add_atom,
121 DictEntry {
122 value: Value::Builtin(add_builtin),
123 is_executable: true,
124 doc: Some(Rc::<str>::from(
125 "Add two numbers or concatenate strings.\nUsage: a b + => result\nExamples: 5 3 + => 8\n\"Hello \" \"World\" + => \"Hello World\"",
126 )),
127 },
128 );
129
130 let sub_atom = interp.intern_atom("-");
131 interp.dictionary.insert(
132 sub_atom,
133 DictEntry {
134 value: Value::Builtin(sub_builtin),
135 is_executable: true,
136 doc: Some(Rc::<str>::from(
137 "Subtract two numbers.\nUsage: a b - => result\nExample: 10 3 - => 7",
138 )),
139 },
140 );
141
142 let mul_atom = interp.intern_atom("*");
143 interp.dictionary.insert(
144 mul_atom,
145 DictEntry {
146 value: Value::Builtin(mul_builtin),
147 is_executable: true,
148 doc: Some(Rc::<str>::from(
149 "Multiply two numbers.\nUsage: a b * => result\nExample: 6 7 * => 42",
150 )),
151 },
152 );
153
154 let div_atom = interp.intern_atom("/");
155 interp.dictionary.insert(
156 div_atom,
157 DictEntry {
158 value: Value::Builtin(div_builtin),
159 is_executable: true,
160 doc: Some(Rc::<str>::from(
161 "Divide two numbers.\nUsage: a b / => result\nExample: 15 3 / => 5",
162 )),
163 },
164 );
165
166 let floor_div_atom = interp.intern_atom("//");
167 interp.dictionary.insert(
168 floor_div_atom,
169 DictEntry {
170 value: Value::Builtin(floor_div_builtin),
171 is_executable: true,
172 doc: Some(Rc::<str>::from(
173 "Floor division (like Python's //).\nUsage: a b // => result\nExample: 7 2 // => 3, -7 2 // => -4",
174 )),
175 },
176 );
177
178 let mod_atom = interp.intern_atom("mod");
179 interp.dictionary.insert(
180 mod_atom,
181 DictEntry {
182 value: Value::Builtin(mod_builtin),
183 is_executable: true,
184 doc: Some(Rc::<str>::from(
185 "Calculate modulo (remainder after division).\nUsage: a b mod => remainder\nExample: 10 3 mod => 1",
186 )),
187 },
188 );
189
190 let trunc_div_atom = interp.intern_atom("div");
191 interp.dictionary.insert(
192 trunc_div_atom,
193 DictEntry {
194 value: Value::Builtin(trunc_div_builtin),
195 is_executable: true,
196 doc: Some(Rc::<str>::from(
197 "Truncating integer division (rounds toward zero).\nUsage: a b div => result\nExample: 7 2 div => 3, -7 2 div => -3",
198 )),
199 },
200 );
201
202 let eq_atom = interp.intern_atom("=");
203 interp.dictionary.insert(
204 eq_atom,
205 DictEntry {
206 value: Value::Builtin(eq_builtin),
207 is_executable: true,
208 doc: Some(Rc::<str>::from(
209 "Test equality of two values.\nUsage: a b = => boolean\nExample: 5 5 = => true",
210 )),
211 },
212 );
213
214 let roll_atom = interp.intern_atom("roll");
216 interp.dictionary.insert(
217 roll_atom,
218 DictEntry {
219 value: Value::Builtin(roll_builtin),
220 is_executable: true,
221 doc: Some(Rc::<str>::from(
222 "Rotate n-th stack item to top.\nUsage: x1 x2 ... xn n roll => x2 ... xn x1\nExample: 1 2 3 2 roll => 2 3 1",
223 )),
224 },
225 );
226
227 let pick_atom = interp.intern_atom("pick");
228 interp.dictionary.insert(
229 pick_atom,
230 DictEntry {
231 value: Value::Builtin(pick_builtin),
232 is_executable: true,
233 doc: Some(Rc::<str>::from(
234 "Copy n-th stack item to top.\nUsage: x1 x2 ... xn n pick => x1 x2 ... xn x1\nExample: 1 2 3 2 pick => 1 2 3 1",
235 )),
236 },
237 );
238
239 let drop_atom = interp.intern_atom("drop");
240 interp.dictionary.insert(
241 drop_atom,
242 DictEntry {
243 value: Value::Builtin(drop_builtin),
244 is_executable: true,
245 doc: Some(Rc::<str>::from(
246 "Remove top stack item.\nUsage: x drop =>\nExample: 1 2 3 drop => 1 2",
247 )),
248 },
249 );
250
251 let def_atom = interp.intern_atom("def");
255 interp.dictionary.insert(
256 def_atom,
257 DictEntry {
258 value: Value::Builtin(def_builtin),
259 is_executable: true,
260 doc: Some(Rc::<str>::from(
261 "Define an executable word. Usage: 'name body def",
262 )),
263 },
264 );
265
266 let val_atom = interp.intern_atom("val");
267 interp.dictionary.insert(
268 val_atom,
269 DictEntry {
270 value: Value::Builtin(val_builtin),
271 is_executable: true,
272 doc: Some(Rc::<str>::from(
273 "Define a constant value. Usage: 'name value val",
274 )),
275 },
276 );
277
278 let doc_atom = interp.intern_atom("doc");
279 interp.dictionary.insert(
280 doc_atom,
281 DictEntry {
282 value: Value::Builtin(doc_builtin),
283 is_executable: true,
284 doc: Some(Rc::<str>::from(
285 "Attach documentation to the most recent def/val.\nUsage: \"lines\" doc",
286 )),
287 },
288 );
289
290 let help_atom = interp.intern_atom("help");
291 interp.dictionary.insert(
292 help_atom,
293 DictEntry {
294 value: Value::Builtin(help_builtin),
295 is_executable: true,
296 doc: Some(Rc::<str>::from(
297 "Display documentation for a word. Usage: 'name help",
298 )),
299 },
300 );
301
302 let print_atom = interp.intern_atom(".");
304 interp.dictionary.insert(
305 print_atom,
306 DictEntry {
307 value: Value::Builtin(print_builtin),
308 is_executable: true,
309 doc: Some(Rc::<str>::from(
310 "Print top stack value to output.\nUsage: value . => (prints value)\nExample: \"Hello\" . => Hello",
311 )),
312 },
313 );
314
315 let words_atom = interp.intern_atom("words");
316 interp.dictionary.insert(
317 words_atom,
318 DictEntry {
319 value: Value::Builtin(words_builtin),
320 is_executable: true,
321 doc: Some(Rc::<str>::from(
322 "Display all defined words in the dictionary.\nUsage: words => (displays all words)\nExample: words => Defined words (120): ...",
323 )),
324 },
325 );
326
327 let stack_atom = interp.intern_atom("stack");
329 interp.dictionary.insert(
330 stack_atom,
331 DictEntry {
332 value: Value::Builtin(stack_builtin),
333 is_executable: true,
334 doc: Some(Rc::<str>::from(
335 "Display the current stack contents.\nUsage: stack => (displays stack)\nExample: 1 2 3 stack => Stack (3 items): ...",
336 )),
337 },
338 );
339
340 let clear_atom = interp.intern_atom("clear");
341 interp.dictionary.insert(
342 clear_atom,
343 DictEntry {
344 value: Value::Builtin(clear_builtin),
345 is_executable: true,
346 doc: Some(Rc::<str>::from(
347 "Clear all items from the stack.\nUsage: clear => (empties stack)\nExample: 1 2 3 clear stack => Stack is empty",
348 )),
349 },
350 );
351
352 let i16_buffer_atom = interp.intern_atom("i16-buffer");
354 interp.dictionary.insert(
355 i16_buffer_atom,
356 DictEntry {
357 value: Value::Builtin(i16_buffer_builtin),
358 is_executable: true,
359 doc: Some(Rc::<str>::from(
360 "Create i16 buffer of specified size.\nUsage: size i16-buffer => buffer\nExample: 1024 i16-buffer => #<i16-buffer:1024:[0 0 0 0 0 0 0 0 ...]>",
361 )),
362 },
363 );
364
365 let i16_ref_atom = interp.intern_atom("i16-ref");
366 interp.dictionary.insert(
367 i16_ref_atom,
368 DictEntry {
369 value: Value::Builtin(i16_ref_builtin),
370 is_executable: true,
371 doc: Some(Rc::<str>::from(
372 "Get value at index from i16 buffer.\nUsage: buffer index i16-ref => value\nExample: buffer 0 i16-ref => 100",
373 )),
374 },
375 );
376
377 let i16_set_atom = interp.intern_atom("i16-set!");
378 interp.dictionary.insert(
379 i16_set_atom,
380 DictEntry {
381 value: Value::Builtin(i16_set_builtin),
382 is_executable: true,
383 doc: Some(Rc::<str>::from(
384 "Set value at index in i16 buffer.\nUsage: value buffer index i16-set! => buffer\nExample: 100 buffer 0 i16-set! => buffer",
385 )),
386 },
387 );
388
389 let i16_length_atom = interp.intern_atom("i16-length");
390 interp.dictionary.insert(
391 i16_length_atom,
392 DictEntry {
393 value: Value::Builtin(i16_length_builtin),
394 is_executable: true,
395 doc: Some(Rc::<str>::from(
396 "Get length of i16 buffer.\nUsage: buffer i16-length => buffer length\nExample: buffer i16-length => buffer 1024",
397 )),
398 },
399 );
400
401 let i16_push_atom = interp.intern_atom("i16-push!");
402 interp.dictionary.insert(
403 i16_push_atom,
404 DictEntry {
405 value: Value::Builtin(i16_push_builtin),
406 is_executable: true,
407 doc: Some(Rc::<str>::from(
408 "Append value to end of i16 buffer.\nUsage: value buffer i16-push! => buffer\nExample: 100 buffer i16-push! => buffer",
409 )),
410 },
411 );
412
413 let i16_pop_atom = interp.intern_atom("i16-pop!");
414 interp.dictionary.insert(
415 i16_pop_atom,
416 DictEntry {
417 value: Value::Builtin(i16_pop_builtin),
418 is_executable: true,
419 doc: Some(Rc::<str>::from(
420 "Remove and return last value from i16 buffer.\nUsage: buffer i16-pop! => buffer value\nExample: buffer i16-pop! => buffer 100",
421 )),
422 },
423 );
424
425 let i16_max_atom = interp.intern_atom("i16-max");
426 interp.dictionary.insert(
427 i16_max_atom,
428 DictEntry {
429 value: Value::Builtin(i16_max_builtin),
430 is_executable: true,
431 doc: Some(Rc::<str>::from(
432 "Find maximum value in i16 buffer.\nUsage: buffer i16-max => buffer max-value\nExample: buffer i16-max => buffer 1000",
433 )),
434 },
435 );
436
437 let i16_min_atom = interp.intern_atom("i16-min");
438 interp.dictionary.insert(
439 i16_min_atom,
440 DictEntry {
441 value: Value::Builtin(i16_min_builtin),
442 is_executable: true,
443 doc: Some(Rc::<str>::from(
444 "Find minimum value in i16 buffer.\nUsage: buffer i16-min => buffer min-value\nExample: buffer i16-min => buffer -500",
445 )),
446 },
447 );
448
449 let i16_avg_atom = interp.intern_atom("i16-avg");
450 interp.dictionary.insert(
451 i16_avg_atom,
452 DictEntry {
453 value: Value::Builtin(i16_avg_builtin),
454 is_executable: true,
455 doc: Some(Rc::<str>::from(
456 "Compute average value of i16 buffer.\nUsage: buffer i16-avg => buffer average\nExample: buffer i16-avg => buffer 250",
457 )),
458 },
459 );
460
461 let to_string_atom = interp.intern_atom("->string");
463 interp.dictionary.insert(
464 to_string_atom,
465 DictEntry {
466 value: Value::Builtin(to_string_builtin),
467 is_executable: true,
468 doc: Some(Rc::<str>::from(
469 "Convert value to string representation.\nUsage: value ->string => string\nExample: 42 ->string => \"42\"",
470 )),
471 },
472 );
473
474 let head_atom = interp.intern_atom("head");
476 interp.dictionary.insert(
477 head_atom,
478 DictEntry {
479 value: Value::Builtin(head_builtin),
480 is_executable: true,
481 doc: Some(Rc::<str>::from(
482 "Get first element of a list.\nUsage: [x y z] head => x\nExample: [1 2 3] head => 1",
483 )),
484 },
485 );
486
487 let tail_atom = interp.intern_atom("tail");
488 interp.dictionary.insert(
489 tail_atom,
490 DictEntry {
491 value: Value::Builtin(tail_builtin),
492 is_executable: true,
493 doc: Some(Rc::<str>::from(
494 "Get all but first element of a list.\nUsage: [x y z] tail => [y z]\nExample: [1 2 3] tail => [2 3]",
495 )),
496 },
497 );
498
499 let cons_atom = interp.intern_atom("cons");
500 interp.dictionary.insert(
501 cons_atom,
502 DictEntry {
503 value: Value::Builtin(cons_builtin),
504 is_executable: true,
505 doc: Some(Rc::<str>::from(
506 "Prepend element to list (construct cons cell).\nUsage: x [y z] cons => [x y z]\nExample: 1 [2 3] cons => [1 2 3]",
507 )),
508 },
509 );
510
511 let list_atom = interp.intern_atom("list");
512 interp.dictionary.insert(
513 list_atom,
514 DictEntry {
515 value: Value::Builtin(list_builtin),
516 is_executable: true,
517 doc: Some(Rc::<str>::from(
518 "Convert all stack items into a list.\nUsage: x y z n list => [x y z]\nExample: 1 2 3 3 list => [1 2 3]",
519 )),
520 },
521 );
522
523 let vector_atom = interp.intern_atom("vector");
524 interp.dictionary.insert(
525 vector_atom,
526 DictEntry {
527 value: Value::Builtin(vector_builtin),
528 is_executable: true,
529 doc: Some(Rc::<str>::from(
530 "Create vector from stack items.\nUsage: x y z n vector => #[x y z]\nExample: 1 2 3 3 vector => #[1 2 3]",
531 )),
532 },
533 );
534
535 let make_vector_atom = interp.intern_atom("make-vector");
536 interp.dictionary.insert(
537 make_vector_atom,
538 DictEntry {
539 value: Value::Builtin(make_vector_builtin),
540 is_executable: true,
541 doc: Some(Rc::<str>::from(
542 "Create vector of size n filled with value.\nUsage: n value make-vector => #[value ...]\nExample: 3 0 make-vector => #[0 0 0]",
543 )),
544 },
545 );
546
547 let vector_length_atom = interp.intern_atom("vector-length");
548 interp.dictionary.insert(
549 vector_length_atom,
550 DictEntry {
551 value: Value::Builtin(vector_length_builtin),
552 is_executable: true,
553 doc: Some(Rc::<str>::from(
554 "Get length of a vector.\nUsage: #[a b c] vector-length => 3\nExample: #[1 2 3] vector-length => 3",
555 )),
556 },
557 );
558
559 let vector_ref_atom = interp.intern_atom("vector-ref");
560 interp.dictionary.insert(
561 vector_ref_atom,
562 DictEntry {
563 value: Value::Builtin(vector_ref_builtin),
564 is_executable: true,
565 doc: Some(Rc::<str>::from(
566 "Get element at index from vector.\nUsage: #[a b c] i vector-ref => element\nExample: #[10 20 30] 1 vector-ref => 20",
567 )),
568 },
569 );
570
571 let vector_set_atom = interp.intern_atom("vector-set!");
572 interp.dictionary.insert(
573 vector_set_atom,
574 DictEntry {
575 value: Value::Builtin(vector_set_builtin),
576 is_executable: true,
577 doc: Some(Rc::<str>::from(
578 "Set element at index in vector.\nUsage: value #[a b c] i vector-set! => #[a value c]\nExample: 99 #[10 20 30] 1 vector-set! => #[10 99 30]",
579 )),
580 },
581 );
582
583 let vector_to_list_atom = interp.intern_atom("vector->list");
584 interp.dictionary.insert(
585 vector_to_list_atom,
586 DictEntry {
587 value: Value::Builtin(vector_to_list_builtin),
588 is_executable: true,
589 doc: Some(Rc::<str>::from(
590 "Convert vector to list.\nUsage: #[a b c] vector->list => [a b c]\nExample: #[1 2 3] vector->list => [1 2 3]",
591 )),
592 },
593 );
594
595 let list_to_vector_atom = interp.intern_atom("list->vector");
596 interp.dictionary.insert(
597 list_to_vector_atom,
598 DictEntry {
599 value: Value::Builtin(list_to_vector_builtin),
600 is_executable: true,
601 doc: Some(Rc::<str>::from(
602 "Convert list to vector.\nUsage: [a b c] list->vector => #[a b c]\nExample: [1 2 3] list->vector => #[1 2 3]",
603 )),
604 },
605 );
606
607 let null_predicate_atom = interp.intern_atom("null?");
609 interp.dictionary.insert(
610 null_predicate_atom,
611 DictEntry {
612 value: Value::Builtin(null_predicate_builtin),
613 is_executable: true,
614 doc: Some(Rc::<str>::from(
615 "Test if value is null.\nUsage: value null? => boolean\nExample: null null? => true",
616 )),
617 },
618 );
619
620 let truthy_predicate_atom = interp.intern_atom("truthy?");
621 interp.dictionary.insert(
622 truthy_predicate_atom,
623 DictEntry {
624 value: Value::Builtin(truthy_predicate_builtin),
625 is_executable: true,
626 doc: Some(Rc::<str>::from(
627 "Test if value is truthy (non-null, non-false, non-zero).\nUsage: value truthy? => boolean\nExample: 5 truthy? => true",
628 )),
629 },
630 );
631
632 let type_of_atom = interp.intern_atom("type");
633 interp.dictionary.insert(
634 type_of_atom,
635 DictEntry {
636 value: Value::Builtin(type_of_builtin),
637 is_executable: true,
638 doc: Some(Rc::<str>::from(
639 "( x -- string ) Return type name of value as a string.\nTypes: number, integer, rational, gaussian, complex, atom, string, boolean, null, list, vector, nil, builtin",
640 )),
641 },
642 );
643
644 let less_than_atom = interp.intern_atom("<");
646 interp.dictionary.insert(
647 less_than_atom,
648 DictEntry {
649 value: Value::Builtin(less_than_builtin),
650 is_executable: true,
651 doc: Some(Rc::<str>::from(
652 "Test if first number is less than second.\nUsage: a b < => boolean\nExample: 3 5 < => true",
653 )),
654 },
655 );
656
657 let greater_than_atom = interp.intern_atom(">");
658 interp.dictionary.insert(
659 greater_than_atom,
660 DictEntry {
661 value: Value::Builtin(greater_than_builtin),
662 is_executable: true,
663 doc: Some(Rc::<str>::from(
664 "Test if first number is greater than second.\nUsage: a b > => boolean\nExample: 5 3 > => true",
665 )),
666 },
667 );
668
669 let less_equal_atom = interp.intern_atom("<=");
670 interp.dictionary.insert(
671 less_equal_atom,
672 DictEntry {
673 value: Value::Builtin(less_equal_builtin),
674 is_executable: true,
675 doc: Some(Rc::<str>::from(
676 "Test if first number is less than or equal to second.\nUsage: a b <= => boolean\nExample: 3 3 <= => true",
677 )),
678 },
679 );
680
681 let greater_equal_atom = interp.intern_atom(">=");
682 interp.dictionary.insert(
683 greater_equal_atom,
684 DictEntry {
685 value: Value::Builtin(greater_equal_builtin),
686 is_executable: true,
687 doc: Some(Rc::<str>::from(
688 "Test if first number is greater than or equal to second.\nUsage: a b >= => boolean\nExample: 5 5 >= => true",
689 )),
690 },
691 );
692
693 let not_equal_atom = interp.intern_atom("!=");
694 interp.dictionary.insert(
695 not_equal_atom,
696 DictEntry {
697 value: Value::Builtin(not_equal_builtin),
698 is_executable: true,
699 doc: Some(Rc::<str>::from(
700 "Test if two values are not equal.\nUsage: a b != => boolean\nExample: 5 3 != => true",
701 )),
702 },
703 );
704
705 let abs_atom = interp.intern_atom("abs");
707 interp.dictionary.insert(
708 abs_atom,
709 DictEntry {
710 value: Value::Builtin(abs_builtin),
711 is_executable: true,
712 doc: Some(Rc::<str>::from(
713 "Calculate absolute value.\nUsage: n abs => |n|\nExample: -5 abs => 5",
714 )),
715 },
716 );
717
718 let min_atom = interp.intern_atom("min");
719 interp.dictionary.insert(
720 min_atom,
721 DictEntry {
722 value: Value::Builtin(min_builtin),
723 is_executable: true,
724 doc: Some(Rc::<str>::from(
725 "Return minimum of two numbers.\nUsage: a b min => min(a,b)\nExample: 3 7 min => 3",
726 )),
727 },
728 );
729
730 let max_atom = interp.intern_atom("max");
731 interp.dictionary.insert(
732 max_atom,
733 DictEntry {
734 value: Value::Builtin(max_builtin),
735 is_executable: true,
736 doc: Some(Rc::<str>::from(
737 "Return maximum of two numbers.\nUsage: a b max => max(a,b)\nExample: 3 7 max => 7",
738 )),
739 },
740 );
741
742 #[cfg(feature = "advanced_math")]
743 {
744 let sqrt_atom = interp.intern_atom("sqrt");
745 interp.dictionary.insert(
746 sqrt_atom,
747 DictEntry {
748 value: Value::Builtin(sqrt_builtin),
749 is_executable: true,
750 doc: Some(Rc::<str>::from(
751 "Calculate square root.\nUsage: n sqrt => √n\nExample: 16 sqrt => 4",
752 )),
753 },
754 );
755 }
756
757 #[cfg(feature = "advanced_math")]
759 {
760 let pow_atom = interp.intern_atom("pow");
761 interp.dictionary.insert(
762 pow_atom,
763 DictEntry {
764 value: Value::Builtin(pow_builtin),
765 is_executable: true,
766 doc: Some(Rc::<str>::from(
767 "Raise number to power.\nUsage: base exponent pow => base^exponent\nExample: 2 8 pow => 256",
768 )),
769 },
770 );
771 }
772
773 #[cfg(feature = "advanced_math")]
774 {
775 let floor_atom = interp.intern_atom("floor");
776 interp.dictionary.insert(
777 floor_atom,
778 DictEntry {
779 value: Value::Builtin(floor_builtin),
780 is_executable: true,
781 doc: Some(Rc::<str>::from(
782 "Round down to nearest integer.\nUsage: n floor => ⌊n⌋\nExample: 3.7 floor => 3",
783 )),
784 },
785 );
786 }
787
788 #[cfg(feature = "advanced_math")]
789 {
790 let ceil_atom = interp.intern_atom("ceil");
791 interp.dictionary.insert(
792 ceil_atom,
793 DictEntry {
794 value: Value::Builtin(ceil_builtin),
795 is_executable: true,
796 doc: Some(Rc::<str>::from(
797 "Round up to nearest integer.\nUsage: n ceil => ⌈n⌉\nExample: 3.2 ceil => 4",
798 )),
799 },
800 );
801 }
802
803 #[cfg(feature = "advanced_math")]
804 {
805 let round_atom = interp.intern_atom("round");
806 interp.dictionary.insert(
807 round_atom,
808 DictEntry {
809 value: Value::Builtin(round_builtin),
810 is_executable: true,
811 doc: Some(Rc::<str>::from(
812 "Round to nearest integer.\nUsage: n round => round(n)\nExample: 3.5 round => 4",
813 )),
814 },
815 );
816 }
817
818 #[cfg(feature = "advanced_math")]
820 {
821 let sin_atom = interp.intern_atom("sin");
822 interp.dictionary.insert(
823 sin_atom,
824 DictEntry {
825 value: Value::Builtin(sin_builtin),
826 is_executable: true,
827 doc: Some(Rc::<str>::from(
828 "Calculate sine (radians).\nUsage: radians sin => sin(radians)\nExample: 0 sin => 0",
829 )),
830 },
831 );
832 }
833
834 #[cfg(feature = "advanced_math")]
835 {
836 let cos_atom = interp.intern_atom("cos");
837 interp.dictionary.insert(
838 cos_atom,
839 DictEntry {
840 value: Value::Builtin(cos_builtin),
841 is_executable: true,
842 doc: Some(Rc::<str>::from(
843 "Calculate cosine (radians).\nUsage: radians cos => cos(radians)\nExample: 0 cos => 1",
844 )),
845 },
846 );
847 }
848
849 #[cfg(feature = "advanced_math")]
850 {
851 let tan_atom = interp.intern_atom("tan");
852 interp.dictionary.insert(
853 tan_atom,
854 DictEntry {
855 value: Value::Builtin(tan_builtin),
856 is_executable: true,
857 doc: Some(Rc::<str>::from(
858 "Calculate tangent (radians).\nUsage: radians tan => tan(radians)\nExample: 0 tan => 0",
859 )),
860 },
861 );
862 }
863
864 #[cfg(feature = "advanced_math")]
866 {
867 let log_atom = interp.intern_atom("log");
868 interp.dictionary.insert(
869 log_atom,
870 DictEntry {
871 value: Value::Builtin(log_builtin),
872 is_executable: true,
873 doc: Some(Rc::<str>::from(
874 "Calculate natural logarithm.\nUsage: n log => ln(n)\nExample: 2.718281828 log => 1",
875 )),
876 },
877 );
878 }
879
880 #[cfg(feature = "advanced_math")]
881 {
882 let exp_atom = interp.intern_atom("exp");
883 interp.dictionary.insert(
884 exp_atom,
885 DictEntry {
886 value: Value::Builtin(exp_builtin),
887 is_executable: true,
888 doc: Some(Rc::<str>::from(
889 "Calculate e raised to power.\nUsage: n exp => e^n\nExample: 1 exp => 2.718281828",
890 )),
891 },
892 );
893 }
894
895 let bit_and_atom = interp.intern_atom("bit-and");
897 interp.dictionary.insert(
898 bit_and_atom,
899 DictEntry {
900 value: Value::Builtin(bit_and_builtin),
901 is_executable: true,
902 doc: Some(Rc::<str>::from(
903 "Bitwise AND of two integers.\nUsage: a b bit-and => a&b\nExample: 12 10 bit-and => 8",
904 )),
905 },
906 );
907
908 let bit_or_atom = interp.intern_atom("bit-or");
909 interp.dictionary.insert(
910 bit_or_atom,
911 DictEntry {
912 value: Value::Builtin(bit_or_builtin),
913 is_executable: true,
914 doc: Some(Rc::<str>::from(
915 "Bitwise OR of two integers.\nUsage: a b bit-or => a|b\nExample: 12 10 bit-or => 14",
916 )),
917 },
918 );
919
920 let bit_xor_atom = interp.intern_atom("bit-xor");
921 interp.dictionary.insert(
922 bit_xor_atom,
923 DictEntry {
924 value: Value::Builtin(bit_xor_builtin),
925 is_executable: true,
926 doc: Some(Rc::<str>::from(
927 "Bitwise XOR of two integers.\nUsage: a b bit-xor => a^b\nExample: 12 10 bit-xor => 6",
928 )),
929 },
930 );
931
932 let bit_not_atom = interp.intern_atom("bit-not");
933 interp.dictionary.insert(
934 bit_not_atom,
935 DictEntry {
936 value: Value::Builtin(bit_not_builtin),
937 is_executable: true,
938 doc: Some(Rc::<str>::from(
939 "Bitwise NOT (complement) of integer.\nUsage: n bit-not => ~n\nExample: 5 bit-not => -6",
940 )),
941 },
942 );
943
944 let shl_atom = interp.intern_atom("shl");
946 interp.dictionary.insert(
947 shl_atom,
948 DictEntry {
949 value: Value::Builtin(shl_builtin),
950 is_executable: true,
951 doc: Some(Rc::<str>::from(
952 "Shift bits left.\nUsage: n count shl => n<<count\nExample: 5 2 shl => 20",
953 )),
954 },
955 );
956
957 let shr_atom = interp.intern_atom("shr");
958 interp.dictionary.insert(
959 shr_atom,
960 DictEntry {
961 value: Value::Builtin(shr_builtin),
962 is_executable: true,
963 doc: Some(Rc::<str>::from(
964 "Shift bits right.\nUsage: n count shr => n>>count\nExample: 20 2 shr => 5",
965 )),
966 },
967 );
968
969 let to_r_atom = interp.intern_atom(">r");
971 interp.dictionary.insert(
972 to_r_atom,
973 DictEntry {
974 value: Value::Builtin(to_r_builtin),
975 is_executable: true,
976 doc: Some(Rc::<str>::from(
977 "Move value from data stack to return stack.\nUsage: x >r => (moves x to return stack)\nExample: 5 >r => (5 now on return stack)",
978 )),
979 },
980 );
981
982 let from_r_atom = interp.intern_atom("r>");
983 interp.dictionary.insert(
984 from_r_atom,
985 DictEntry {
986 value: Value::Builtin(from_r_builtin),
987 is_executable: true,
988 doc: Some(Rc::<str>::from(
989 "Move value from return stack to data stack.\nUsage: r> => x\nExample: r> => (moves top of return stack to data stack)",
990 )),
991 },
992 );
993
994 let r_fetch_atom = interp.intern_atom("r@");
995 interp.dictionary.insert(
996 r_fetch_atom,
997 DictEntry {
998 value: Value::Builtin(r_fetch_builtin),
999 is_executable: true,
1000 doc: Some(Rc::<str>::from(
1001 "Copy top of return stack to data stack.\nUsage: r@ => x\nExample: r@ => (copies top of return stack without removing it)",
1002 )),
1003 },
1004 );
1005
1006 let make_record_type_atom = interp.intern_atom("make-record-type");
1008 interp.dictionary.insert(
1009 make_record_type_atom,
1010 DictEntry {
1011 value: Value::Builtin(make_record_type_builtin),
1012 is_executable: true,
1013 doc: Some(Rc::<str>::from(
1014 "Create a record type with named fields.\nUsage: [field-names...] \"type-name\" make-record-type => record-type\nExample: [\"name\" \"age\"] \"person\" make-record-type",
1015 )),
1016 },
1017 );
1018
1019 let construct_record_atom = interp.intern_atom("construct-record");
1020 interp.dictionary.insert(
1021 construct_record_atom,
1022 DictEntry {
1023 value: Value::Builtin(construct_record_builtin),
1024 is_executable: true,
1025 doc: Some(Rc::<str>::from(
1026 "Internal helper to construct record instances.\nUsage: field-values... n \"type-name\" construct-record => record",
1027 )),
1028 },
1029 );
1030
1031 let is_record_type_atom = interp.intern_atom("is-record-type?");
1032 interp.dictionary.insert(
1033 is_record_type_atom,
1034 DictEntry {
1035 value: Value::Builtin(is_record_type_builtin),
1036 is_executable: true,
1037 doc: Some(Rc::<str>::from(
1038 "Check if value is a record of specific type.\nUsage: value \"type-name\" is-record-type? => boolean",
1039 )),
1040 },
1041 );
1042
1043 let get_record_field_atom = interp.intern_atom("get-record-field");
1044 interp.dictionary.insert(
1045 get_record_field_atom,
1046 DictEntry {
1047 value: Value::Builtin(get_record_field_builtin),
1048 is_executable: true,
1049 doc: Some(Rc::<str>::from(
1050 "Get field value from record.\nUsage: record \"type-name\" field-index get-record-field => value",
1051 )),
1052 },
1053 );
1054
1055 let set_record_field_atom = interp.intern_atom("set-record-field!");
1056 interp.dictionary.insert(
1057 set_record_field_atom,
1058 DictEntry {
1059 value: Value::Builtin(set_record_field_builtin),
1060 is_executable: true,
1061 doc: Some(Rc::<str>::from(
1062 "Set field value in record.\nUsage: new-value record \"type-name\" field-index set-record-field! => record",
1063 )),
1064 },
1065 );
1066
1067 let record_type_of_atom = interp.intern_atom("record-type-of");
1068 interp.dictionary.insert(
1069 record_type_of_atom,
1070 DictEntry {
1071 value: Value::Builtin(record_type_of_builtin),
1072 is_executable: true,
1073 doc: Some(Rc::<str>::from(
1074 "Get type name from record instance.\nUsage: record record-type-of => \"type-name\"",
1075 )),
1076 },
1077 );
1078
1079 #[cfg(feature = "datetime")]
1081 {
1082 let now_atom = interp.intern_atom("now");
1083 interp.dictionary.insert(
1084 now_atom,
1085 DictEntry {
1086 value: Value::Builtin(now_builtin),
1087 is_executable: true,
1088 doc: Some(Rc::<str>::from(
1089 "Get current date/time in local timezone.\nUsage: now => datetime",
1090 )),
1091 },
1092 );
1093
1094 let datetime_atom = interp.intern_atom("datetime");
1095 interp.dictionary.insert(
1096 datetime_atom,
1097 DictEntry {
1098 value: Value::Builtin(datetime_builtin),
1099 is_executable: true,
1100 doc: Some(Rc::<str>::from(
1101 "Create datetime in local timezone.\nUsage: year month day hour minute second datetime => datetime\nExample: 2025 10 1 14 30 0 datetime",
1102 )),
1103 },
1104 );
1105
1106 let datetime_with_offset_atom = interp.intern_atom("datetime-with-offset");
1107 interp.dictionary.insert(
1108 datetime_with_offset_atom,
1109 DictEntry {
1110 value: Value::Builtin(datetime_with_offset_builtin),
1111 is_executable: true,
1112 doc: Some(Rc::<str>::from(
1113 "Create datetime with specific offset.\nUsage: year month day hour minute second offset-hours datetime-with-offset => datetime\nExample: 2025 10 1 14 30 0 -5 datetime-with-offset",
1114 )),
1115 },
1116 );
1117
1118 let year_atom = interp.intern_atom("year");
1119 interp.dictionary.insert(
1120 year_atom,
1121 DictEntry {
1122 value: Value::Builtin(year_builtin),
1123 is_executable: true,
1124 doc: Some(Rc::<str>::from(
1125 "Extract year from datetime.\nUsage: datetime year => year",
1126 )),
1127 },
1128 );
1129
1130 let month_atom = interp.intern_atom("month");
1131 interp.dictionary.insert(
1132 month_atom,
1133 DictEntry {
1134 value: Value::Builtin(month_builtin),
1135 is_executable: true,
1136 doc: Some(Rc::<str>::from(
1137 "Extract month (1-12) from datetime.\nUsage: datetime month => month",
1138 )),
1139 },
1140 );
1141
1142 let day_atom = interp.intern_atom("day");
1143 interp.dictionary.insert(
1144 day_atom,
1145 DictEntry {
1146 value: Value::Builtin(day_builtin),
1147 is_executable: true,
1148 doc: Some(Rc::<str>::from(
1149 "Extract day (1-31) from datetime.\nUsage: datetime day => day",
1150 )),
1151 },
1152 );
1153
1154 let hour_atom = interp.intern_atom("hour");
1155 interp.dictionary.insert(
1156 hour_atom,
1157 DictEntry {
1158 value: Value::Builtin(hour_builtin),
1159 is_executable: true,
1160 doc: Some(Rc::<str>::from(
1161 "Extract hour (0-23) from datetime.\nUsage: datetime hour => hour",
1162 )),
1163 },
1164 );
1165
1166 let minute_atom = interp.intern_atom("minute");
1167 interp.dictionary.insert(
1168 minute_atom,
1169 DictEntry {
1170 value: Value::Builtin(minute_builtin),
1171 is_executable: true,
1172 doc: Some(Rc::<str>::from(
1173 "Extract minute (0-59) from datetime.\nUsage: datetime minute => minute",
1174 )),
1175 },
1176 );
1177
1178 let second_atom = interp.intern_atom("second");
1179 interp.dictionary.insert(
1180 second_atom,
1181 DictEntry {
1182 value: Value::Builtin(second_builtin),
1183 is_executable: true,
1184 doc: Some(Rc::<str>::from(
1185 "Extract second (0-59) from datetime.\nUsage: datetime second => second",
1186 )),
1187 },
1188 );
1189
1190 let weekday_atom = interp.intern_atom("weekday");
1191 interp.dictionary.insert(
1192 weekday_atom,
1193 DictEntry {
1194 value: Value::Builtin(weekday_builtin),
1195 is_executable: true,
1196 doc: Some(Rc::<str>::from(
1197 "Get day of week (0=Monday, 6=Sunday) from datetime.\nUsage: datetime weekday => weekday",
1198 )),
1199 },
1200 );
1201
1202 let timestamp_atom = interp.intern_atom("timestamp");
1203 interp.dictionary.insert(
1204 timestamp_atom,
1205 DictEntry {
1206 value: Value::Builtin(timestamp_builtin),
1207 is_executable: true,
1208 doc: Some(Rc::<str>::from(
1209 "Convert datetime to Unix timestamp (seconds since epoch).\nUsage: datetime timestamp => timestamp",
1210 )),
1211 },
1212 );
1213
1214 let timestamp_to_datetime_atom = interp.intern_atom("timestamp->datetime");
1215 interp.dictionary.insert(
1216 timestamp_to_datetime_atom,
1217 DictEntry {
1218 value: Value::Builtin(timestamp_to_datetime_builtin),
1219 is_executable: true,
1220 doc: Some(Rc::<str>::from(
1221 "Convert Unix timestamp to datetime in local timezone.\nUsage: timestamp timestamp->datetime => datetime",
1222 )),
1223 },
1224 );
1225
1226 let to_utc_atom = interp.intern_atom("to-utc");
1227 interp.dictionary.insert(
1228 to_utc_atom,
1229 DictEntry {
1230 value: Value::Builtin(to_utc_builtin),
1231 is_executable: true,
1232 doc: Some(Rc::<str>::from(
1233 "Convert datetime to UTC.\nUsage: datetime to-utc => datetime",
1234 )),
1235 },
1236 );
1237
1238 let to_local_atom = interp.intern_atom("to-local");
1239 interp.dictionary.insert(
1240 to_local_atom,
1241 DictEntry {
1242 value: Value::Builtin(to_local_builtin),
1243 is_executable: true,
1244 doc: Some(Rc::<str>::from(
1245 "Convert datetime to local timezone.\nUsage: datetime to-local => datetime",
1246 )),
1247 },
1248 );
1249
1250 let datetime_to_string_atom = interp.intern_atom("datetime->string");
1251 interp.dictionary.insert(
1252 datetime_to_string_atom,
1253 DictEntry {
1254 value: Value::Builtin(datetime_to_string_builtin),
1255 is_executable: true,
1256 doc: Some(Rc::<str>::from(
1257 "Format datetime as ISO 8601 string.\nUsage: datetime datetime->string => string",
1258 )),
1259 },
1260 );
1261
1262 let string_to_datetime_atom = interp.intern_atom("string->datetime");
1263 interp.dictionary.insert(
1264 string_to_datetime_atom,
1265 DictEntry {
1266 value: Value::Builtin(string_to_datetime_builtin),
1267 is_executable: true,
1268 doc: Some(Rc::<str>::from(
1269 "Parse ISO 8601 string to datetime.\nUsage: string string->datetime => datetime",
1270 )),
1271 },
1272 );
1273
1274 let date_less_than_atom = interp.intern_atom("date<");
1275 interp.dictionary.insert(
1276 date_less_than_atom,
1277 DictEntry {
1278 value: Value::Builtin(date_less_than_builtin),
1279 is_executable: true,
1280 doc: Some(Rc::<str>::from(
1281 "Compare datetimes (less than).\nUsage: datetime1 datetime2 date< => boolean",
1282 )),
1283 },
1284 );
1285
1286 let date_greater_than_atom = interp.intern_atom("date>");
1287 interp.dictionary.insert(
1288 date_greater_than_atom,
1289 DictEntry {
1290 value: Value::Builtin(date_greater_than_builtin),
1291 is_executable: true,
1292 doc: Some(Rc::<str>::from(
1293 "Compare datetimes (greater than).\nUsage: datetime1 datetime2 date> => boolean",
1294 )),
1295 },
1296 );
1297
1298 let date_equal_atom = interp.intern_atom("date=");
1299 interp.dictionary.insert(
1300 date_equal_atom,
1301 DictEntry {
1302 value: Value::Builtin(date_equal_builtin),
1303 is_executable: true,
1304 doc: Some(Rc::<str>::from(
1305 "Compare datetimes (equal).\nUsage: datetime1 datetime2 date= => boolean",
1306 )),
1307 },
1308 );
1309
1310 let duration_atom = interp.intern_atom("duration");
1312 interp.dictionary.insert(
1313 duration_atom,
1314 DictEntry {
1315 value: Value::Builtin(duration_builtin),
1316 is_executable: true,
1317 doc: Some(Rc::<str>::from(
1318 "Create duration from components.\nUsage: days hours minutes seconds duration => duration\nExample: 1 2 30 0 duration",
1319 )),
1320 },
1321 );
1322
1323 let duration_to_seconds_atom = interp.intern_atom("duration->seconds");
1324 interp.dictionary.insert(
1325 duration_to_seconds_atom,
1326 DictEntry {
1327 value: Value::Builtin(duration_to_seconds_builtin),
1328 is_executable: true,
1329 doc: Some(Rc::<str>::from(
1330 "Convert duration to total seconds.\nUsage: duration duration->seconds => seconds",
1331 )),
1332 },
1333 );
1334
1335 let date_add_atom = interp.intern_atom("date+");
1336 interp.dictionary.insert(
1337 date_add_atom,
1338 DictEntry {
1339 value: Value::Builtin(date_add_builtin),
1340 is_executable: true,
1341 doc: Some(Rc::<str>::from(
1342 "Add duration to datetime.\nUsage: datetime duration date+ => datetime",
1343 )),
1344 },
1345 );
1346
1347 let date_sub_atom = interp.intern_atom("date-");
1348 interp.dictionary.insert(
1349 date_sub_atom,
1350 DictEntry {
1351 value: Value::Builtin(date_sub_builtin),
1352 is_executable: true,
1353 doc: Some(Rc::<str>::from(
1354 "Subtract datetime or duration.\nUsage: datetime1 datetime2 date- => duration (time between)\nUsage: datetime duration date- => datetime (subtract duration)",
1355 )),
1356 },
1357 );
1358
1359 let duration_less_than_atom = interp.intern_atom("duration<");
1360 interp.dictionary.insert(
1361 duration_less_than_atom,
1362 DictEntry {
1363 value: Value::Builtin(duration_less_than_builtin),
1364 is_executable: true,
1365 doc: Some(Rc::<str>::from(
1366 "Compare durations (less than).\nUsage: duration1 duration2 duration< => boolean",
1367 )),
1368 },
1369 );
1370
1371 let duration_greater_than_atom = interp.intern_atom("duration>");
1372 interp.dictionary.insert(
1373 duration_greater_than_atom,
1374 DictEntry {
1375 value: Value::Builtin(duration_greater_than_builtin),
1376 is_executable: true,
1377 doc: Some(Rc::<str>::from(
1378 "Compare durations (greater than).\nUsage: duration1 duration2 duration> => boolean",
1379 )),
1380 },
1381 );
1382
1383 let duration_equal_atom = interp.intern_atom("duration=");
1384 interp.dictionary.insert(
1385 duration_equal_atom,
1386 DictEntry {
1387 value: Value::Builtin(duration_equal_builtin),
1388 is_executable: true,
1389 doc: Some(Rc::<str>::from(
1390 "Compare durations (equal).\nUsage: duration1 duration2 duration= => boolean",
1391 )),
1392 },
1393 );
1394 } #[cfg(feature = "hardware-microbit")]
1398 crate::hardware::microbit::register_microbit_primitives(interp);
1399
1400 #[cfg(feature = "hardware-pico")]
1401 crate::hardware::pico::register_pico_primitives(interp);
1402}
1403
1404#[cfg(test)]
1405mod tests {
1406 use super::*;
1407 use crate::interpreter::DictEntry;
1408
1409 fn setup_interpreter() -> Interpreter {
1410 Interpreter::new()
1411 }
1412
1413 #[test]
1414 fn test_all_builtins_registered() {
1415 let mut interp = setup_interpreter();
1416
1417 let expected_builtins = [
1418 "+", "-", "*", "/", "//", "div", "mod", "=", "<", ">", "<=", ">=", "!=", "abs", "min", "max", "sqrt", "pow", "floor", "ceil", "round", "sin", "cos", "tan", "log", "exp", "bit-and", "bit-or", "bit-xor", "bit-not", "shl", "shr", "roll", "pick", "drop", ">r", "r>", "r@", "def", "val", ".", "->string", "head", "tail", "cons", "list", "truthy?",
1435 ];
1436
1437 for builtin_name in expected_builtins.iter() {
1438 let atom = interp.intern_atom(builtin_name);
1439 assert!(
1440 interp.dictionary.contains_key(&atom),
1441 "Expected builtin '{}' to be registered",
1442 builtin_name
1443 );
1444
1445 assert!(matches!(
1447 interp.dictionary.get(&atom),
1448 Some(DictEntry {
1449 value: Value::Builtin(_),
1450 ..
1451 })
1452 ));
1453 }
1454 }
1455}