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 cr_builtin,
20 def_builtin,
22 div_builtin,
23 doc_builtin,
24 drop_builtin,
26 eq_builtin,
27 fetch_builtin, floor_div_builtin,
30 from_r_builtin,
31 get_record_field_builtin,
32 greater_equal_builtin,
33 greater_than_builtin,
34 head_builtin,
35 help_builtin,
36 is_record_type_builtin,
37 less_equal_builtin,
38 lval_builtin,
40 lvar_builtin,
41 less_than_builtin,
43 list_builtin,
44 list_to_vector_builtin,
45 make_record_type_builtin,
46 make_vector_builtin,
47 max_builtin,
48 min_builtin,
49 mod_builtin,
50 mul_builtin,
51 not_equal_builtin,
52 null_predicate_builtin,
53 pick_builtin,
54 print_builtin,
57 words_builtin,
58 clear_builtin,
60 stack_builtin,
61 r_fetch_builtin,
62 record_type_of_builtin,
63 roll_builtin,
64 set_record_field_builtin,
65 shl_builtin,
67 shr_builtin,
68 space_builtin,
69 store_builtin, sub_builtin,
71 tail_builtin,
72 to_r_builtin,
74 to_string_builtin,
76 trunc_div_builtin,
77 truthy_predicate_builtin,
79 type_of_builtin,
81 val_builtin,
82 var_builtin,
83 vector_builtin,
84 vector_length_builtin,
85 vector_ref_builtin,
86 vector_set_builtin,
87 vector_to_list_builtin,
88};
89
90#[cfg(feature = "advanced_math")]
92use crate::primitives::{
93 ceil_builtin,
94 cos_builtin,
95 exp_builtin,
96 floor_builtin,
97 log_builtin,
98 pow_builtin,
99 round_builtin,
100 sin_builtin,
101 sqrt_builtin,
102 tan_builtin,
103};
104
105use crate::primitives::now_builtin;
107
108use crate::primitives::{
110 i16_avg_builtin, i16_buffer_builtin, i16_length_builtin, i16_max_builtin, i16_min_builtin,
111 i16_pop_builtin, i16_push_builtin, i16_ref_builtin, i16_set_builtin,
112};
113
114pub fn register_builtins(interp: &mut Interpreter) {
116 use crate::interpreter::DictEntry;
117
118 let add_atom = interp.intern_atom("+");
120 interp.dictionary.insert(
121 add_atom,
122 DictEntry {
123 value: Value::Builtin(add_builtin),
124 is_executable: true,
125 doc: Some(Rc::<str>::from(
126 "Add two numbers or concatenate strings.\nUsage: a b + => result\nExamples: 5 3 + => 8\n\"Hello \" \"World\" + => \"Hello World\"",
127 )),
128 },
129 );
130
131 let sub_atom = interp.intern_atom("-");
132 interp.dictionary.insert(
133 sub_atom,
134 DictEntry {
135 value: Value::Builtin(sub_builtin),
136 is_executable: true,
137 doc: Some(Rc::<str>::from(
138 "Subtract two numbers.\nUsage: a b - => result\nExample: 10 3 - => 7",
139 )),
140 },
141 );
142
143 let mul_atom = interp.intern_atom("*");
144 interp.dictionary.insert(
145 mul_atom,
146 DictEntry {
147 value: Value::Builtin(mul_builtin),
148 is_executable: true,
149 doc: Some(Rc::<str>::from(
150 "Multiply two numbers.\nUsage: a b * => result\nExample: 6 7 * => 42",
151 )),
152 },
153 );
154
155 let div_atom = interp.intern_atom("/");
156 interp.dictionary.insert(
157 div_atom,
158 DictEntry {
159 value: Value::Builtin(div_builtin),
160 is_executable: true,
161 doc: Some(Rc::<str>::from(
162 "Divide two numbers.\nUsage: a b / => result\nExample: 15 3 / => 5",
163 )),
164 },
165 );
166
167 let floor_div_atom = interp.intern_atom("//");
168 interp.dictionary.insert(
169 floor_div_atom,
170 DictEntry {
171 value: Value::Builtin(floor_div_builtin),
172 is_executable: true,
173 doc: Some(Rc::<str>::from(
174 "Floor division (like Python's //).\nUsage: a b // => result\nExample: 7 2 // => 3, -7 2 // => -4",
175 )),
176 },
177 );
178
179 let mod_atom = interp.intern_atom("mod");
180 interp.dictionary.insert(
181 mod_atom,
182 DictEntry {
183 value: Value::Builtin(mod_builtin),
184 is_executable: true,
185 doc: Some(Rc::<str>::from(
186 "Calculate modulo (remainder after division).\nUsage: a b mod => remainder\nExample: 10 3 mod => 1",
187 )),
188 },
189 );
190
191 let trunc_div_atom = interp.intern_atom("div");
192 interp.dictionary.insert(
193 trunc_div_atom,
194 DictEntry {
195 value: Value::Builtin(trunc_div_builtin),
196 is_executable: true,
197 doc: Some(Rc::<str>::from(
198 "Truncating integer division (rounds toward zero).\nUsage: a b div => result\nExample: 7 2 div => 3, -7 2 div => -3",
199 )),
200 },
201 );
202
203 let eq_atom = interp.intern_atom("=");
204 interp.dictionary.insert(
205 eq_atom,
206 DictEntry {
207 value: Value::Builtin(eq_builtin),
208 is_executable: true,
209 doc: Some(Rc::<str>::from(
210 "Test equality of two values.\nUsage: a b = => boolean\nExample: 5 5 = => true",
211 )),
212 },
213 );
214
215 let roll_atom = interp.intern_atom("roll");
217 interp.dictionary.insert(
218 roll_atom,
219 DictEntry {
220 value: Value::Builtin(roll_builtin),
221 is_executable: true,
222 doc: Some(Rc::<str>::from(
223 "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",
224 )),
225 },
226 );
227
228 let pick_atom = interp.intern_atom("pick");
229 interp.dictionary.insert(
230 pick_atom,
231 DictEntry {
232 value: Value::Builtin(pick_builtin),
233 is_executable: true,
234 doc: Some(Rc::<str>::from(
235 "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",
236 )),
237 },
238 );
239
240 let drop_atom = interp.intern_atom("drop");
241 interp.dictionary.insert(
242 drop_atom,
243 DictEntry {
244 value: Value::Builtin(drop_builtin),
245 is_executable: true,
246 doc: Some(Rc::<str>::from(
247 "Remove top stack item.\nUsage: x drop =>\nExample: 1 2 3 drop => 1 2",
248 )),
249 },
250 );
251
252 let def_atom = interp.intern_atom("def");
256 interp.dictionary.insert(
257 def_atom,
258 DictEntry {
259 value: Value::Builtin(def_builtin),
260 is_executable: true,
261 doc: Some(Rc::<str>::from(
262 "Define an executable word. Usage: 'name body def",
263 )),
264 },
265 );
266
267 let val_atom = interp.intern_atom("val");
268 interp.dictionary.insert(
269 val_atom,
270 DictEntry {
271 value: Value::Builtin(val_builtin),
272 is_executable: true,
273 doc: Some(Rc::<str>::from(
274 "Define a constant value. Usage: 'name value val",
275 )),
276 },
277 );
278
279 let var_atom = interp.intern_atom("var");
281 interp.dictionary.insert(
282 var_atom,
283 DictEntry {
284 value: Value::Builtin(var_builtin),
285 is_executable: true,
286 doc: Some(Rc::<str>::from(
287 "Create a mutable variable.\nUsage: initial-value 'name var\nExample: 0 'counter var",
288 )),
289 },
290 );
291
292 let fetch_atom = interp.intern_atom("@");
293 interp.dictionary.insert(
294 fetch_atom,
295 DictEntry {
296 value: Value::Builtin(fetch_builtin),
297 is_executable: true,
298 doc: Some(Rc::<str>::from(
299 "Fetch value from variable.\nUsage: var @ => value\nExample: counter @ .",
300 )),
301 },
302 );
303
304 let store_atom = interp.intern_atom("!");
305 interp.dictionary.insert(
306 store_atom,
307 DictEntry {
308 value: Value::Builtin(store_builtin),
309 is_executable: true,
310 doc: Some(Rc::<str>::from(
311 "Store value into variable.\nUsage: value var !\nExample: 42 counter !",
312 )),
313 },
314 );
315
316 let lval_atom = interp.intern_atom("lval");
318 interp.dictionary.insert(
319 lval_atom,
320 DictEntry {
321 value: Value::Builtin(lval_builtin),
322 is_executable: true,
323 doc: Some(Rc::<str>::from(
324 "Create a local constant in current quotation.\nUsage: value 'name lval\nExample: 42 'x lval x .",
325 )),
326 },
327 );
328
329 let lvar_atom = interp.intern_atom("lvar");
330 interp.dictionary.insert(
331 lvar_atom,
332 DictEntry {
333 value: Value::Builtin(lvar_builtin),
334 is_executable: true,
335 doc: Some(Rc::<str>::from(
336 "Create a local mutable variable in current quotation.\nUsage: value 'name lvar\nExample: 0 'count lvar count @ 1 + count !",
337 )),
338 },
339 );
340
341 let doc_atom = interp.intern_atom("doc");
342 interp.dictionary.insert(
343 doc_atom,
344 DictEntry {
345 value: Value::Builtin(doc_builtin),
346 is_executable: true,
347 doc: Some(Rc::<str>::from(
348 "Attach documentation to the most recent def/val.\nUsage: \"lines\" doc",
349 )),
350 },
351 );
352
353 let help_atom = interp.intern_atom("help");
354 interp.dictionary.insert(
355 help_atom,
356 DictEntry {
357 value: Value::Builtin(help_builtin),
358 is_executable: true,
359 doc: Some(Rc::<str>::from(
360 "Display documentation for a word. Usage: 'name help",
361 )),
362 },
363 );
364
365 let print_atom = interp.intern_atom(".");
367 interp.dictionary.insert(
368 print_atom,
369 DictEntry {
370 value: Value::Builtin(print_builtin),
371 is_executable: true,
372 doc: Some(Rc::<str>::from(
373 "Print top stack value to output.\nUsage: value . => (prints value)\nExample: \"Hello\" . => Hello",
374 )),
375 },
376 );
377
378 let words_atom = interp.intern_atom("words");
379 interp.dictionary.insert(
380 words_atom,
381 DictEntry {
382 value: Value::Builtin(words_builtin),
383 is_executable: true,
384 doc: Some(Rc::<str>::from(
385 "Display all defined words in the dictionary.\nUsage: words => (displays all words)\nExample: words => Defined words (120): ...",
386 )),
387 },
388 );
389
390 let cr_atom = interp.intern_atom("cr");
391 interp.dictionary.insert(
392 cr_atom,
393 DictEntry {
394 value: Value::Builtin(cr_builtin),
395 is_executable: true,
396 doc: Some(Rc::<str>::from(
397 "Output a newline character.\nUsage: cr => (outputs newline)\nExample: \"Hello\" . cr \"World\" . cr",
398 )),
399 },
400 );
401
402 let space_atom = interp.intern_atom("space");
403 interp.dictionary.insert(
404 space_atom,
405 DictEntry {
406 value: Value::Builtin(space_builtin),
407 is_executable: true,
408 doc: Some(Rc::<str>::from(
409 "Output a space character.\nUsage: space => (outputs space)\nExample: \"Hello\" . space \"World\" .",
410 )),
411 },
412 );
413
414 let stack_atom = interp.intern_atom("stack");
416 interp.dictionary.insert(
417 stack_atom,
418 DictEntry {
419 value: Value::Builtin(stack_builtin),
420 is_executable: true,
421 doc: Some(Rc::<str>::from(
422 "Display the current stack contents.\nUsage: stack => (displays stack)\nExample: 1 2 3 stack => Stack (3 items): ...",
423 )),
424 },
425 );
426
427 let clear_atom = interp.intern_atom("clear");
428 interp.dictionary.insert(
429 clear_atom,
430 DictEntry {
431 value: Value::Builtin(clear_builtin),
432 is_executable: true,
433 doc: Some(Rc::<str>::from(
434 "Clear all items from the stack.\nUsage: clear => (empties stack)\nExample: 1 2 3 clear stack => Stack is empty",
435 )),
436 },
437 );
438
439 let i16_buffer_atom = interp.intern_atom("i16-buffer");
441 interp.dictionary.insert(
442 i16_buffer_atom,
443 DictEntry {
444 value: Value::Builtin(i16_buffer_builtin),
445 is_executable: true,
446 doc: Some(Rc::<str>::from(
447 "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 ...]>",
448 )),
449 },
450 );
451
452 let i16_ref_atom = interp.intern_atom("i16-ref");
453 interp.dictionary.insert(
454 i16_ref_atom,
455 DictEntry {
456 value: Value::Builtin(i16_ref_builtin),
457 is_executable: true,
458 doc: Some(Rc::<str>::from(
459 "Get value at index from i16 buffer.\nUsage: buffer index i16-ref => value\nExample: buffer 0 i16-ref => 100",
460 )),
461 },
462 );
463
464 let i16_set_atom = interp.intern_atom("i16-set!");
465 interp.dictionary.insert(
466 i16_set_atom,
467 DictEntry {
468 value: Value::Builtin(i16_set_builtin),
469 is_executable: true,
470 doc: Some(Rc::<str>::from(
471 "Set value at index in i16 buffer.\nUsage: value buffer index i16-set! => buffer\nExample: 100 buffer 0 i16-set! => buffer",
472 )),
473 },
474 );
475
476 let i16_length_atom = interp.intern_atom("i16-length");
477 interp.dictionary.insert(
478 i16_length_atom,
479 DictEntry {
480 value: Value::Builtin(i16_length_builtin),
481 is_executable: true,
482 doc: Some(Rc::<str>::from(
483 "Get length of i16 buffer.\nUsage: buffer i16-length => buffer length\nExample: buffer i16-length => buffer 1024",
484 )),
485 },
486 );
487
488 let i16_push_atom = interp.intern_atom("i16-push!");
489 interp.dictionary.insert(
490 i16_push_atom,
491 DictEntry {
492 value: Value::Builtin(i16_push_builtin),
493 is_executable: true,
494 doc: Some(Rc::<str>::from(
495 "Append value to end of i16 buffer.\nUsage: value buffer i16-push! => buffer\nExample: 100 buffer i16-push! => buffer",
496 )),
497 },
498 );
499
500 let i16_pop_atom = interp.intern_atom("i16-pop!");
501 interp.dictionary.insert(
502 i16_pop_atom,
503 DictEntry {
504 value: Value::Builtin(i16_pop_builtin),
505 is_executable: true,
506 doc: Some(Rc::<str>::from(
507 "Remove and return last value from i16 buffer.\nUsage: buffer i16-pop! => buffer value\nExample: buffer i16-pop! => buffer 100",
508 )),
509 },
510 );
511
512 let i16_max_atom = interp.intern_atom("i16-max");
513 interp.dictionary.insert(
514 i16_max_atom,
515 DictEntry {
516 value: Value::Builtin(i16_max_builtin),
517 is_executable: true,
518 doc: Some(Rc::<str>::from(
519 "Find maximum value in i16 buffer.\nUsage: buffer i16-max => buffer max-value\nExample: buffer i16-max => buffer 1000",
520 )),
521 },
522 );
523
524 let i16_min_atom = interp.intern_atom("i16-min");
525 interp.dictionary.insert(
526 i16_min_atom,
527 DictEntry {
528 value: Value::Builtin(i16_min_builtin),
529 is_executable: true,
530 doc: Some(Rc::<str>::from(
531 "Find minimum value in i16 buffer.\nUsage: buffer i16-min => buffer min-value\nExample: buffer i16-min => buffer -500",
532 )),
533 },
534 );
535
536 let i16_avg_atom = interp.intern_atom("i16-avg");
537 interp.dictionary.insert(
538 i16_avg_atom,
539 DictEntry {
540 value: Value::Builtin(i16_avg_builtin),
541 is_executable: true,
542 doc: Some(Rc::<str>::from(
543 "Compute average value of i16 buffer.\nUsage: buffer i16-avg => buffer average\nExample: buffer i16-avg => buffer 250",
544 )),
545 },
546 );
547
548 let now_atom = interp.intern_atom("now");
550 interp.dictionary.insert(
551 now_atom,
552 DictEntry {
553 value: Value::Builtin(now_builtin),
554 is_executable: true,
555 doc: Some(Rc::<str>::from(
556 "Get current date and time as a date record.\nUsage: now => #<record:date year month day hour minute second offset>\nRequires platform to inject TimeSource.\nExample: now => #<record:date 2025 10 18 14 30 0 -240>",
557 )),
558 },
559 );
560
561 let to_string_atom = interp.intern_atom("->string");
563 interp.dictionary.insert(
564 to_string_atom,
565 DictEntry {
566 value: Value::Builtin(to_string_builtin),
567 is_executable: true,
568 doc: Some(Rc::<str>::from(
569 "Convert value to string representation.\nUsage: value ->string => string\nExample: 42 ->string => \"42\"",
570 )),
571 },
572 );
573
574 let head_atom = interp.intern_atom("head");
576 interp.dictionary.insert(
577 head_atom,
578 DictEntry {
579 value: Value::Builtin(head_builtin),
580 is_executable: true,
581 doc: Some(Rc::<str>::from(
582 "Get first element of a list.\nUsage: [x y z] head => x\nExample: [1 2 3] head => 1",
583 )),
584 },
585 );
586
587 let tail_atom = interp.intern_atom("tail");
588 interp.dictionary.insert(
589 tail_atom,
590 DictEntry {
591 value: Value::Builtin(tail_builtin),
592 is_executable: true,
593 doc: Some(Rc::<str>::from(
594 "Get all but first element of a list.\nUsage: [x y z] tail => [y z]\nExample: [1 2 3] tail => [2 3]",
595 )),
596 },
597 );
598
599 let cons_atom = interp.intern_atom("cons");
600 interp.dictionary.insert(
601 cons_atom,
602 DictEntry {
603 value: Value::Builtin(cons_builtin),
604 is_executable: true,
605 doc: Some(Rc::<str>::from(
606 "Prepend element to list (construct cons cell).\nUsage: x [y z] cons => [x y z]\nExample: 1 [2 3] cons => [1 2 3]",
607 )),
608 },
609 );
610
611 let list_atom = interp.intern_atom("list");
612 interp.dictionary.insert(
613 list_atom,
614 DictEntry {
615 value: Value::Builtin(list_builtin),
616 is_executable: true,
617 doc: Some(Rc::<str>::from(
618 "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]",
619 )),
620 },
621 );
622
623 let vector_atom = interp.intern_atom("vector");
624 interp.dictionary.insert(
625 vector_atom,
626 DictEntry {
627 value: Value::Builtin(vector_builtin),
628 is_executable: true,
629 doc: Some(Rc::<str>::from(
630 "Create vector from stack items.\nUsage: x y z n vector => #[x y z]\nExample: 1 2 3 3 vector => #[1 2 3]",
631 )),
632 },
633 );
634
635 let make_vector_atom = interp.intern_atom("make-vector");
636 interp.dictionary.insert(
637 make_vector_atom,
638 DictEntry {
639 value: Value::Builtin(make_vector_builtin),
640 is_executable: true,
641 doc: Some(Rc::<str>::from(
642 "Create vector of size n filled with value.\nUsage: n value make-vector => #[value ...]\nExample: 3 0 make-vector => #[0 0 0]",
643 )),
644 },
645 );
646
647 let vector_length_atom = interp.intern_atom("vector-length");
648 interp.dictionary.insert(
649 vector_length_atom,
650 DictEntry {
651 value: Value::Builtin(vector_length_builtin),
652 is_executable: true,
653 doc: Some(Rc::<str>::from(
654 "Get length of a vector.\nUsage: #[a b c] vector-length => 3\nExample: #[1 2 3] vector-length => 3",
655 )),
656 },
657 );
658
659 let vector_ref_atom = interp.intern_atom("vector-ref");
660 interp.dictionary.insert(
661 vector_ref_atom,
662 DictEntry {
663 value: Value::Builtin(vector_ref_builtin),
664 is_executable: true,
665 doc: Some(Rc::<str>::from(
666 "Get element at index from vector.\nUsage: #[a b c] i vector-ref => element\nExample: #[10 20 30] 1 vector-ref => 20",
667 )),
668 },
669 );
670
671 let vector_set_atom = interp.intern_atom("vector-set!");
672 interp.dictionary.insert(
673 vector_set_atom,
674 DictEntry {
675 value: Value::Builtin(vector_set_builtin),
676 is_executable: true,
677 doc: Some(Rc::<str>::from(
678 "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]",
679 )),
680 },
681 );
682
683 let vector_to_list_atom = interp.intern_atom("vector->list");
684 interp.dictionary.insert(
685 vector_to_list_atom,
686 DictEntry {
687 value: Value::Builtin(vector_to_list_builtin),
688 is_executable: true,
689 doc: Some(Rc::<str>::from(
690 "Convert vector to list.\nUsage: #[a b c] vector->list => [a b c]\nExample: #[1 2 3] vector->list => [1 2 3]",
691 )),
692 },
693 );
694
695 let list_to_vector_atom = interp.intern_atom("list->vector");
696 interp.dictionary.insert(
697 list_to_vector_atom,
698 DictEntry {
699 value: Value::Builtin(list_to_vector_builtin),
700 is_executable: true,
701 doc: Some(Rc::<str>::from(
702 "Convert list to vector.\nUsage: [a b c] list->vector => #[a b c]\nExample: [1 2 3] list->vector => #[1 2 3]",
703 )),
704 },
705 );
706
707 let null_predicate_atom = interp.intern_atom("null?");
709 interp.dictionary.insert(
710 null_predicate_atom,
711 DictEntry {
712 value: Value::Builtin(null_predicate_builtin),
713 is_executable: true,
714 doc: Some(Rc::<str>::from(
715 "Test if value is null.\nUsage: value null? => boolean\nExample: null null? => true",
716 )),
717 },
718 );
719
720 let truthy_predicate_atom = interp.intern_atom("truthy?");
721 interp.dictionary.insert(
722 truthy_predicate_atom,
723 DictEntry {
724 value: Value::Builtin(truthy_predicate_builtin),
725 is_executable: true,
726 doc: Some(Rc::<str>::from(
727 "Test if value is truthy (non-null, non-false, non-zero).\nUsage: value truthy? => boolean\nExample: 5 truthy? => true",
728 )),
729 },
730 );
731
732 let type_of_atom = interp.intern_atom("type");
733 interp.dictionary.insert(
734 type_of_atom,
735 DictEntry {
736 value: Value::Builtin(type_of_builtin),
737 is_executable: true,
738 doc: Some(Rc::<str>::from(
739 "( x -- string ) Return type name of value as a string.\nTypes: number, integer, rational, gaussian, complex, atom, string, boolean, null, list, vector, nil, builtin",
740 )),
741 },
742 );
743
744 let less_than_atom = interp.intern_atom("<");
746 interp.dictionary.insert(
747 less_than_atom,
748 DictEntry {
749 value: Value::Builtin(less_than_builtin),
750 is_executable: true,
751 doc: Some(Rc::<str>::from(
752 "Test if first number is less than second.\nUsage: a b < => boolean\nExample: 3 5 < => true",
753 )),
754 },
755 );
756
757 let greater_than_atom = interp.intern_atom(">");
758 interp.dictionary.insert(
759 greater_than_atom,
760 DictEntry {
761 value: Value::Builtin(greater_than_builtin),
762 is_executable: true,
763 doc: Some(Rc::<str>::from(
764 "Test if first number is greater than second.\nUsage: a b > => boolean\nExample: 5 3 > => true",
765 )),
766 },
767 );
768
769 let less_equal_atom = interp.intern_atom("<=");
770 interp.dictionary.insert(
771 less_equal_atom,
772 DictEntry {
773 value: Value::Builtin(less_equal_builtin),
774 is_executable: true,
775 doc: Some(Rc::<str>::from(
776 "Test if first number is less than or equal to second.\nUsage: a b <= => boolean\nExample: 3 3 <= => true",
777 )),
778 },
779 );
780
781 let greater_equal_atom = interp.intern_atom(">=");
782 interp.dictionary.insert(
783 greater_equal_atom,
784 DictEntry {
785 value: Value::Builtin(greater_equal_builtin),
786 is_executable: true,
787 doc: Some(Rc::<str>::from(
788 "Test if first number is greater than or equal to second.\nUsage: a b >= => boolean\nExample: 5 5 >= => true",
789 )),
790 },
791 );
792
793 let not_equal_atom = interp.intern_atom("!=");
794 interp.dictionary.insert(
795 not_equal_atom,
796 DictEntry {
797 value: Value::Builtin(not_equal_builtin),
798 is_executable: true,
799 doc: Some(Rc::<str>::from(
800 "Test if two values are not equal.\nUsage: a b != => boolean\nExample: 5 3 != => true",
801 )),
802 },
803 );
804
805 let abs_atom = interp.intern_atom("abs");
807 interp.dictionary.insert(
808 abs_atom,
809 DictEntry {
810 value: Value::Builtin(abs_builtin),
811 is_executable: true,
812 doc: Some(Rc::<str>::from(
813 "Calculate absolute value.\nUsage: n abs => |n|\nExample: -5 abs => 5",
814 )),
815 },
816 );
817
818 let min_atom = interp.intern_atom("min");
819 interp.dictionary.insert(
820 min_atom,
821 DictEntry {
822 value: Value::Builtin(min_builtin),
823 is_executable: true,
824 doc: Some(Rc::<str>::from(
825 "Return minimum of two numbers.\nUsage: a b min => min(a,b)\nExample: 3 7 min => 3",
826 )),
827 },
828 );
829
830 let max_atom = interp.intern_atom("max");
831 interp.dictionary.insert(
832 max_atom,
833 DictEntry {
834 value: Value::Builtin(max_builtin),
835 is_executable: true,
836 doc: Some(Rc::<str>::from(
837 "Return maximum of two numbers.\nUsage: a b max => max(a,b)\nExample: 3 7 max => 7",
838 )),
839 },
840 );
841
842 #[cfg(feature = "advanced_math")]
843 {
844 let sqrt_atom = interp.intern_atom("sqrt");
845 interp.dictionary.insert(
846 sqrt_atom,
847 DictEntry {
848 value: Value::Builtin(sqrt_builtin),
849 is_executable: true,
850 doc: Some(Rc::<str>::from(
851 "Calculate square root.\nUsage: n sqrt => √n\nExample: 16 sqrt => 4",
852 )),
853 },
854 );
855 }
856
857 #[cfg(feature = "advanced_math")]
859 {
860 let pow_atom = interp.intern_atom("pow");
861 interp.dictionary.insert(
862 pow_atom,
863 DictEntry {
864 value: Value::Builtin(pow_builtin),
865 is_executable: true,
866 doc: Some(Rc::<str>::from(
867 "Raise number to power.\nUsage: base exponent pow => base^exponent\nExample: 2 8 pow => 256",
868 )),
869 },
870 );
871 }
872
873 #[cfg(feature = "advanced_math")]
874 {
875 let floor_atom = interp.intern_atom("floor");
876 interp.dictionary.insert(
877 floor_atom,
878 DictEntry {
879 value: Value::Builtin(floor_builtin),
880 is_executable: true,
881 doc: Some(Rc::<str>::from(
882 "Round down to nearest integer.\nUsage: n floor => ⌊n⌋\nExample: 3.7 floor => 3",
883 )),
884 },
885 );
886 }
887
888 #[cfg(feature = "advanced_math")]
889 {
890 let ceil_atom = interp.intern_atom("ceil");
891 interp.dictionary.insert(
892 ceil_atom,
893 DictEntry {
894 value: Value::Builtin(ceil_builtin),
895 is_executable: true,
896 doc: Some(Rc::<str>::from(
897 "Round up to nearest integer.\nUsage: n ceil => ⌈n⌉\nExample: 3.2 ceil => 4",
898 )),
899 },
900 );
901 }
902
903 #[cfg(feature = "advanced_math")]
904 {
905 let round_atom = interp.intern_atom("round");
906 interp.dictionary.insert(
907 round_atom,
908 DictEntry {
909 value: Value::Builtin(round_builtin),
910 is_executable: true,
911 doc: Some(Rc::<str>::from(
912 "Round to nearest integer.\nUsage: n round => round(n)\nExample: 3.5 round => 4",
913 )),
914 },
915 );
916 }
917
918 #[cfg(feature = "advanced_math")]
920 {
921 let sin_atom = interp.intern_atom("sin");
922 interp.dictionary.insert(
923 sin_atom,
924 DictEntry {
925 value: Value::Builtin(sin_builtin),
926 is_executable: true,
927 doc: Some(Rc::<str>::from(
928 "Calculate sine (radians).\nUsage: radians sin => sin(radians)\nExample: 0 sin => 0",
929 )),
930 },
931 );
932 }
933
934 #[cfg(feature = "advanced_math")]
935 {
936 let cos_atom = interp.intern_atom("cos");
937 interp.dictionary.insert(
938 cos_atom,
939 DictEntry {
940 value: Value::Builtin(cos_builtin),
941 is_executable: true,
942 doc: Some(Rc::<str>::from(
943 "Calculate cosine (radians).\nUsage: radians cos => cos(radians)\nExample: 0 cos => 1",
944 )),
945 },
946 );
947 }
948
949 #[cfg(feature = "advanced_math")]
950 {
951 let tan_atom = interp.intern_atom("tan");
952 interp.dictionary.insert(
953 tan_atom,
954 DictEntry {
955 value: Value::Builtin(tan_builtin),
956 is_executable: true,
957 doc: Some(Rc::<str>::from(
958 "Calculate tangent (radians).\nUsage: radians tan => tan(radians)\nExample: 0 tan => 0",
959 )),
960 },
961 );
962 }
963
964 #[cfg(feature = "advanced_math")]
966 {
967 let log_atom = interp.intern_atom("log");
968 interp.dictionary.insert(
969 log_atom,
970 DictEntry {
971 value: Value::Builtin(log_builtin),
972 is_executable: true,
973 doc: Some(Rc::<str>::from(
974 "Calculate natural logarithm.\nUsage: n log => ln(n)\nExample: 2.718281828 log => 1",
975 )),
976 },
977 );
978 }
979
980 #[cfg(feature = "advanced_math")]
981 {
982 let exp_atom = interp.intern_atom("exp");
983 interp.dictionary.insert(
984 exp_atom,
985 DictEntry {
986 value: Value::Builtin(exp_builtin),
987 is_executable: true,
988 doc: Some(Rc::<str>::from(
989 "Calculate e raised to power.\nUsage: n exp => e^n\nExample: 1 exp => 2.718281828",
990 )),
991 },
992 );
993 }
994
995 let bit_and_atom = interp.intern_atom("bit-and");
997 interp.dictionary.insert(
998 bit_and_atom,
999 DictEntry {
1000 value: Value::Builtin(bit_and_builtin),
1001 is_executable: true,
1002 doc: Some(Rc::<str>::from(
1003 "Bitwise AND of two integers.\nUsage: a b bit-and => a&b\nExample: 12 10 bit-and => 8",
1004 )),
1005 },
1006 );
1007
1008 let bit_or_atom = interp.intern_atom("bit-or");
1009 interp.dictionary.insert(
1010 bit_or_atom,
1011 DictEntry {
1012 value: Value::Builtin(bit_or_builtin),
1013 is_executable: true,
1014 doc: Some(Rc::<str>::from(
1015 "Bitwise OR of two integers.\nUsage: a b bit-or => a|b\nExample: 12 10 bit-or => 14",
1016 )),
1017 },
1018 );
1019
1020 let bit_xor_atom = interp.intern_atom("bit-xor");
1021 interp.dictionary.insert(
1022 bit_xor_atom,
1023 DictEntry {
1024 value: Value::Builtin(bit_xor_builtin),
1025 is_executable: true,
1026 doc: Some(Rc::<str>::from(
1027 "Bitwise XOR of two integers.\nUsage: a b bit-xor => a^b\nExample: 12 10 bit-xor => 6",
1028 )),
1029 },
1030 );
1031
1032 let bit_not_atom = interp.intern_atom("bit-not");
1033 interp.dictionary.insert(
1034 bit_not_atom,
1035 DictEntry {
1036 value: Value::Builtin(bit_not_builtin),
1037 is_executable: true,
1038 doc: Some(Rc::<str>::from(
1039 "Bitwise NOT (complement) of integer.\nUsage: n bit-not => ~n\nExample: 5 bit-not => -6",
1040 )),
1041 },
1042 );
1043
1044 let shl_atom = interp.intern_atom("shl");
1046 interp.dictionary.insert(
1047 shl_atom,
1048 DictEntry {
1049 value: Value::Builtin(shl_builtin),
1050 is_executable: true,
1051 doc: Some(Rc::<str>::from(
1052 "Shift bits left.\nUsage: n count shl => n<<count\nExample: 5 2 shl => 20",
1053 )),
1054 },
1055 );
1056
1057 let shr_atom = interp.intern_atom("shr");
1058 interp.dictionary.insert(
1059 shr_atom,
1060 DictEntry {
1061 value: Value::Builtin(shr_builtin),
1062 is_executable: true,
1063 doc: Some(Rc::<str>::from(
1064 "Shift bits right.\nUsage: n count shr => n>>count\nExample: 20 2 shr => 5",
1065 )),
1066 },
1067 );
1068
1069 let to_r_atom = interp.intern_atom(">r");
1071 interp.dictionary.insert(
1072 to_r_atom,
1073 DictEntry {
1074 value: Value::Builtin(to_r_builtin),
1075 is_executable: true,
1076 doc: Some(Rc::<str>::from(
1077 "Move value from data stack to return stack.\nUsage: x >r => (moves x to return stack)\nExample: 5 >r => (5 now on return stack)",
1078 )),
1079 },
1080 );
1081
1082 let from_r_atom = interp.intern_atom("r>");
1083 interp.dictionary.insert(
1084 from_r_atom,
1085 DictEntry {
1086 value: Value::Builtin(from_r_builtin),
1087 is_executable: true,
1088 doc: Some(Rc::<str>::from(
1089 "Move value from return stack to data stack.\nUsage: r> => x\nExample: r> => (moves top of return stack to data stack)",
1090 )),
1091 },
1092 );
1093
1094 let r_fetch_atom = interp.intern_atom("r@");
1095 interp.dictionary.insert(
1096 r_fetch_atom,
1097 DictEntry {
1098 value: Value::Builtin(r_fetch_builtin),
1099 is_executable: true,
1100 doc: Some(Rc::<str>::from(
1101 "Copy top of return stack to data stack.\nUsage: r@ => x\nExample: r@ => (copies top of return stack without removing it)",
1102 )),
1103 },
1104 );
1105
1106 let make_record_type_atom = interp.intern_atom("make-record-type");
1108 interp.dictionary.insert(
1109 make_record_type_atom,
1110 DictEntry {
1111 value: Value::Builtin(make_record_type_builtin),
1112 is_executable: true,
1113 doc: Some(Rc::<str>::from(
1114 "Create a record type with named fields.\nUsage: [field-names...] \"type-name\" make-record-type => record-type\nExample: [\"name\" \"age\"] \"person\" make-record-type",
1115 )),
1116 },
1117 );
1118
1119 let construct_record_atom = interp.intern_atom("construct-record");
1120 interp.dictionary.insert(
1121 construct_record_atom,
1122 DictEntry {
1123 value: Value::Builtin(construct_record_builtin),
1124 is_executable: true,
1125 doc: Some(Rc::<str>::from(
1126 "Internal helper to construct record instances.\nUsage: field-values... n \"type-name\" construct-record => record",
1127 )),
1128 },
1129 );
1130
1131 let is_record_type_atom = interp.intern_atom("is-record-type?");
1132 interp.dictionary.insert(
1133 is_record_type_atom,
1134 DictEntry {
1135 value: Value::Builtin(is_record_type_builtin),
1136 is_executable: true,
1137 doc: Some(Rc::<str>::from(
1138 "Check if value is a record of specific type.\nUsage: value \"type-name\" is-record-type? => boolean",
1139 )),
1140 },
1141 );
1142
1143 let get_record_field_atom = interp.intern_atom("get-record-field");
1144 interp.dictionary.insert(
1145 get_record_field_atom,
1146 DictEntry {
1147 value: Value::Builtin(get_record_field_builtin),
1148 is_executable: true,
1149 doc: Some(Rc::<str>::from(
1150 "Get field value from record.\nUsage: record \"type-name\" field-index get-record-field => value",
1151 )),
1152 },
1153 );
1154
1155 let set_record_field_atom = interp.intern_atom("set-record-field!");
1156 interp.dictionary.insert(
1157 set_record_field_atom,
1158 DictEntry {
1159 value: Value::Builtin(set_record_field_builtin),
1160 is_executable: true,
1161 doc: Some(Rc::<str>::from(
1162 "Set field value in record.\nUsage: new-value record \"type-name\" field-index set-record-field! => record",
1163 )),
1164 },
1165 );
1166
1167 let record_type_of_atom = interp.intern_atom("record-type-of");
1168 interp.dictionary.insert(
1169 record_type_of_atom,
1170 DictEntry {
1171 value: Value::Builtin(record_type_of_builtin),
1172 is_executable: true,
1173 doc: Some(Rc::<str>::from(
1174 "Get type name from record instance.\nUsage: record record-type-of => \"type-name\"",
1175 )),
1176 },
1177 );
1178
1179 #[cfg(feature = "hardware-pico2")]
1181 crate::hardware::pico2::register_pico2_primitives(interp);
1182
1183}
1184
1185#[cfg(test)]
1186mod tests {
1187 use super::*;
1188 use crate::interpreter::DictEntry;
1189
1190 fn setup_interpreter() -> Interpreter {
1191 Interpreter::new()
1192 }
1193
1194 #[test]
1195 fn test_all_builtins_registered() {
1196 let mut interp = setup_interpreter();
1197
1198 let expected_builtins = [
1199 "+", "-", "*", "/", "//", "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?",
1216 ];
1217
1218 for builtin_name in expected_builtins.iter() {
1219 let atom = interp.intern_atom(builtin_name);
1220 assert!(
1221 interp.dictionary.contains_key(&atom),
1222 "Expected builtin '{}' to be registered",
1223 builtin_name
1224 );
1225
1226 assert!(matches!(
1228 interp.dictionary.get(&atom),
1229 Some(DictEntry {
1230 value: Value::Builtin(_),
1231 ..
1232 })
1233 ));
1234 }
1235 }
1236}