1use crate::evaluator::execute_string;
6use crate::interpreter::Interpreter;
7use crate::value::RuntimeError;
8
9pub fn load_prelude(interp: &mut Interpreter) -> Result<(), RuntimeError> {
12 let prelude_code = r#"
18 \\ Stack manipulation words
19 'swap [1 roll] def
20 "( a b -- b a ) Swap top two stack items" doc
21
22 'dup [0 pick] def
23 "( a -- a a ) Duplicate top stack item" doc
24
25 'over [1 pick] def
26 "( a b -- a b a ) Copy second stack item to top" doc
27
28 'rot [2 roll] def
29 "( a b c -- b c a ) Rotate third item to top" doc
30
31 'nip [swap drop] def
32 "( a b -- b ) Remove second stack item" doc
33
34 'tuck [swap over] def
35 "( a b -- b a b ) Copy top below second item" doc
36
37 'nil? [[] =] def
38 "( x -- bool ) Test if value is empty list" doc
39
40 \\ Logical operations
41 'not [[false] [true] if] def
42 "( x -- bool ) Logical negation of truthiness" doc
43
44 \\ Arithmetic operations
45 'negate [-1 *] def
46 "( n -- -n ) Negate a number" doc
47
48 \\ List processing primitives
49 'length [
50 dup nil?
51 [drop 0]
52 [tail length 1 +]
53 if
54 ] def
55 "( list -- n ) Calculate list length recursively" doc
56
57 'list-ref [
58 dup 0 =
59 [drop head]
60 [1 - swap tail swap list-ref]
61 if
62 ] def
63 "( list index -- element ) Get nth element (0-indexed)" doc
64
65 'append [
66 swap dup nil?
67 [drop]
68 [
69 dup head
70 swap tail
71 rot
72 append
73 cons
74 ]
75 if
76 ] def
77 "( list1 list2 -- list3 ) Concatenate two lists" doc
78
79 'null? [null =] def
80 "( x -- bool ) Test if value is null" doc
81
82 'record? [type "record" =] def
83 "( x -- bool ) Test if value is any record type" doc
84
85 \\ Conditional duplication from Forth
86 '?dup [
87 dup truthy? [dup] [] if
88 ] def
89 "( x -- x x | x ) Duplicate if truthy, otherwise leave unchanged" doc
90
91 \\ Variable operations (Forth-style)
92 '1+ [1 +] def
93 "( n -- n+1 ) Increment by 1" doc
94
95 '1- [1 -] def
96 "( n -- n-1 ) Decrement by 1" doc
97
98 '+! [dup @ rot + swap !] def
99 "( n var -- ) Add n to variable" doc
100
101 'on [true swap !] def
102 "( var -- ) Store true to variable" doc
103
104 'off [false swap !] def
105 "( var -- ) Store false to variable" doc
106
107 \\ List iteration
108 'each [
109 >r \\ Move fn to return stack: list | fn
110 dup nil? \\ Check if list is empty: list bool | fn
111 [
112 drop r> drop \\ Empty list: clean up list and fn
113 ]
114 [
115 dup head \\ list -> list head | fn
116 r@ \\ Get fn: list head fn | fn
117 exec \\ Execute fn: list ... | fn (fn consumes head, may leave results)
118 tail \\ Get tail: ... tail | fn
119 r> each \\ Recurse: ... tail fn
120 ]
121 if
122 ] def
123 "( list [fn] -- ) Execute fn on each element of list (fn consumes argument, may leave results)" doc
124
125 \\ Short-circuiting logical operations
126 'and [
127 swap \\ Move first quotation to top
128 exec \\ Execute first quotation
129 dup \\ Always duplicate the result
130 [
131 drop \\ Drop the duplicate, keep original
132 exec \\ Execute second quotation
133 ]
134 [
135 swap drop \\ If falsy, drop second quotation, keep falsy result
136 ]
137 if
138 ] def
139 "( [cond1] [cond2] -- result ) Short-circuit AND: executes cond2 only if cond1 is truthy" doc
140
141 'or [
142 swap \\ Move first quotation to top
143 exec \\ Execute first quotation
144 dup \\ Always duplicate the result
145 [
146 swap drop \\ If truthy, drop second quotation, keep result
147 ]
148 [
149 drop \\ Drop the duplicate
150 exec \\ If falsy, execute second quotation
151 ]
152 if
153 ] def
154 "( [cond1] [cond2] -- result ) Short-circuit OR: executes cond2 only if cond1 is falsy" doc
155
156 \\ Control flow primitives
157 'while [
158 >r >r \\ move body and condition to return stack
159 r@ exec \\ execute condition (copy from R-stack)
160 [
161 r> r> dup rot swap >r >r \\ get body and move body and condition back to return stack
162 exec \\ execute body
163 r> r> while \\ recursive call
164 ]
165 [ r> r> drop drop ]
166 if
167 ] def
168 "( [condition] [body] -- ) Loop: executes body while condition returns truthy" doc
169
170 \\ Date/time operations
171 \\ Date record type with calendar components
172 \\ The 'now' primitive (written in Rust) returns instances of this record type
173 ["year" "month" "day" "hour" "minute" "second" "offset"] "date" make-record-type drop
174 "#;
175
176 execute_string(prelude_code, interp)?;
179
180 #[cfg(feature = "complex_numbers")]
183 {
184 let complex_prelude = r#"
185 \\ Mathematical constants (complex numbers)
186 'i 0+1i def
187 "Imaginary unit constant (0+1i)" doc
188 "#;
189 execute_string(complex_prelude, interp)?;
190 }
191
192 #[cfg(target_os = "none")]
195 {
196 let hardware_prelude = r#"
197 \\ Hardware convenience wrappers (micro:bit only)
198 'button-a? [0 button-read] def
199 "( -- bool ) Read button A state (true = pressed)" doc
200
201 'button-b? [1 button-read] def
202 "( -- bool ) Read button B state (true = pressed)" doc
203 "#;
204 execute_string(hardware_prelude, interp)?;
205 }
206
207 Ok(())
208}
209
210#[cfg(test)]
212mod tests {
213 use super::*;
214 use crate::value::Value;
215
216 fn setup_interpreter_with_prelude() -> Interpreter {
218 let mut interp = Interpreter::new();
221 load_prelude(&mut interp).unwrap();
222 interp
223 }
224
225 #[test]
226 fn test_prelude_dup() {
227 let mut interp = setup_interpreter_with_prelude();
228
229 execute_string("42 dup", &mut interp).unwrap();
231
232 let top = interp.pop().unwrap();
233 let second = interp.pop().unwrap();
234
235 assert!(matches!(top, Value::Int32(42)));
236 assert!(matches!(second, Value::Int32(42)));
237 }
238
239 #[test]
240 fn test_prelude_swap() {
241 let mut interp = setup_interpreter_with_prelude();
242
243 execute_string("1 2 swap", &mut interp).unwrap();
245
246 let top = interp.pop().unwrap();
247 let second = interp.pop().unwrap();
248
249 assert!(matches!(top, Value::Int32(1)));
250 assert!(matches!(second, Value::Int32(2)));
251 }
252
253 #[test]
254 fn test_prelude_over() {
255 let mut interp = setup_interpreter_with_prelude();
256
257 execute_string("1 2 over", &mut interp).unwrap();
259
260 let top = interp.pop().unwrap();
261 let second = interp.pop().unwrap();
262 let third = interp.pop().unwrap();
263
264 assert!(matches!(top, Value::Int32(1)));
265 assert!(matches!(second, Value::Int32(2)));
266 assert!(matches!(third, Value::Int32(1)));
267 }
268
269 #[test]
270 fn test_prelude_rot() {
271 let mut interp = setup_interpreter_with_prelude();
272
273 execute_string("1 2 3 rot", &mut interp).unwrap();
275
276 let top = interp.pop().unwrap();
277 let second = interp.pop().unwrap();
278 let third = interp.pop().unwrap();
279
280 assert!(matches!(top, Value::Int32(1)));
281 assert!(matches!(second, Value::Int32(3)));
282 assert!(matches!(third, Value::Int32(2)));
283 }
284
285 #[test]
286 fn test_prelude_nip() {
287 let mut interp = setup_interpreter_with_prelude();
288
289 execute_string("1 2 3 nip", &mut interp).unwrap();
291
292 let top = interp.pop().unwrap();
293 let second = interp.pop().unwrap();
294
295 assert!(matches!(top, Value::Int32(3)));
296 assert!(matches!(second, Value::Int32(1)));
297
298 assert!(interp.pop().is_err());
300 }
301
302 #[test]
303 fn test_prelude_tuck() {
304 let mut interp = setup_interpreter_with_prelude();
305
306 execute_string("5 6 tuck", &mut interp).unwrap();
308
309 let top = interp.pop().unwrap();
310 let second = interp.pop().unwrap();
311 let third = interp.pop().unwrap();
312
313 assert!(matches!(top, Value::Int32(6)));
314 assert!(matches!(second, Value::Int32(5)));
315 assert!(matches!(third, Value::Int32(6)));
316
317 assert!(interp.pop().is_err());
319 }
320
321 #[test]
322 fn test_prelude_length() {
323 let mut interp = setup_interpreter_with_prelude();
324
325 execute_string("[1 2 3 4 5] length", &mut interp).unwrap();
327
328 let result = interp.pop().unwrap();
329 assert!(matches!(result, Value::Int32(5)));
330
331 execute_string("[] length", &mut interp).unwrap();
333
334 let result = interp.pop().unwrap();
335 assert!(matches!(result, Value::Int32(0)));
336 }
337
338 #[test]
339 fn test_prelude_null_predicate() {
340 let mut interp = setup_interpreter_with_prelude();
341
342 execute_string("null null?", &mut interp).unwrap();
344
345 let result = interp.pop().unwrap();
346 assert!(matches!(result, Value::Boolean(true)));
347
348 execute_string("42 null?", &mut interp).unwrap();
350
351 let result = interp.pop().unwrap();
352 assert!(matches!(result, Value::Boolean(false)));
353
354 execute_string("[] null?", &mut interp).unwrap();
356
357 let result = interp.pop().unwrap();
358 assert!(matches!(result, Value::Boolean(false)));
359 }
360
361 #[test]
362 fn test_prelude_while_loop_counter() {
363 let mut interp = setup_interpreter_with_prelude();
364
365 let code = r#"
369 1
370 [ dup 5 < ]
371 [ 1 + ]
372 while
373 "#;
374
375 execute_string(code, &mut interp).unwrap();
376
377 let result = interp.pop().unwrap();
379 assert!(matches!(result, Value::Int32(5)));
380
381 assert!(interp.pop().is_err());
383 }
384
385 #[test]
386 fn test_prelude_while_sum_accumulator() {
387 let mut interp = setup_interpreter_with_prelude();
388
389 let code = r#"
392 1 0
393 [ over 5 <= ]
394 [ over + swap 1 + swap ]
395 while
396 nip
397 "#;
398
399 execute_string(code, &mut interp).unwrap();
400
401 let result = interp.pop().unwrap();
403 assert!(matches!(result, Value::Int32(15)));
404
405 assert!(interp.pop().is_err());
407 }
408
409 #[test]
410 fn test_prelude_while_empty_body() {
411 let mut interp = setup_interpreter_with_prelude();
412
413 let code = r#"
415 42
416 [ 0 ]
417 [ 99 ]
418 while
419 "#;
420
421 execute_string(code, &mut interp).unwrap();
422
423 let result = interp.pop().unwrap();
425 assert!(matches!(result, Value::Int32(42)));
426
427 assert!(interp.pop().is_err());
429 }
430
431 #[test]
432 fn test_prelude_question_dup() {
433 let mut interp = setup_interpreter_with_prelude();
434
435 execute_string("42 ?dup", &mut interp).unwrap();
437
438 let top = interp.pop().unwrap();
439 let second = interp.pop().unwrap();
440 assert!(matches!(top, Value::Int32(42)));
441 assert!(matches!(second, Value::Int32(42)));
442
443 execute_string("0 ?dup", &mut interp).unwrap();
445
446 let result = interp.pop().unwrap();
447 assert!(matches!(result, Value::Int32(0)));
448 assert!(interp.pop().is_err());
450
451 execute_string("false ?dup", &mut interp).unwrap();
453
454 let result = interp.pop().unwrap();
455 assert!(matches!(result, Value::Boolean(false)));
456 assert!(interp.pop().is_err());
457 }
458
459 #[test]
460 fn test_prelude_and_short_circuit() {
461 let mut interp = setup_interpreter_with_prelude();
462
463 execute_string("[5] [10] and", &mut interp).unwrap();
465
466 let result = interp.pop().unwrap();
467 assert!(matches!(result, Value::Int32(10)));
468
469 execute_string("[0] [99] and", &mut interp).unwrap();
471
472 let result = interp.pop().unwrap();
473 assert!(matches!(result, Value::Int32(0)));
474
475 execute_string("999 [0] [drop] and", &mut interp).unwrap();
479
480 let and_result = interp.pop().unwrap();
481 let marker = interp.pop().unwrap();
482 assert!(matches!(and_result, Value::Int32(0)));
483 assert!(matches!(marker, Value::Int32(999))); }
485
486 #[test]
487 fn test_prelude_or_short_circuit() {
488 let mut interp = setup_interpreter_with_prelude();
489
490 execute_string("[0] [42] or", &mut interp).unwrap();
492
493 let result = interp.pop().unwrap();
494 assert!(matches!(result, Value::Int32(42)));
495
496 execute_string("[5] [99] or", &mut interp).unwrap();
498
499 let result = interp.pop().unwrap();
500 assert!(matches!(result, Value::Int32(5)));
501
502 execute_string("888 [7] [drop] or", &mut interp).unwrap();
504
505 let or_result = interp.pop().unwrap();
506 let marker = interp.pop().unwrap();
507 assert!(matches!(or_result, Value::Int32(7)));
508 assert!(matches!(marker, Value::Int32(888))); }
510
511 #[test]
512 fn test_prelude_and_or_chaining() {
513 let mut interp = setup_interpreter_with_prelude();
514
515 execute_string("[1] [2] and [3] and", &mut interp).unwrap();
517
518 let result = interp.pop().unwrap();
519 assert!(matches!(result, Value::Int32(3)));
520
521 execute_string("[1] [2] or [3] or", &mut interp).unwrap();
523
524 let result = interp.pop().unwrap();
525 assert!(matches!(result, Value::Int32(1)));
526
527 execute_string("[0] [5] or [10] and", &mut interp).unwrap();
529
530 let result = interp.pop().unwrap();
531 assert!(matches!(result, Value::Int32(10)));
532 }
533
534 #[test]
535 #[cfg(feature = "complex_numbers")]
536 fn test_prelude_imaginary_constant() {
537 use num_bigint::BigInt;
538 let mut interp = setup_interpreter_with_prelude();
539
540 execute_string("i", &mut interp).unwrap();
542
543 let result = interp.pop().unwrap();
544 assert!(matches!(result, Value::GaussianInt(ref re, ref im)
545 if re == &BigInt::from(0) && im == &BigInt::from(1)));
546
547 execute_string("i i +", &mut interp).unwrap();
549
550 let result = interp.pop().unwrap();
551 assert!(matches!(result, Value::GaussianInt(ref re, ref im)
552 if re == &BigInt::from(0) && im == &BigInt::from(2)));
553 }
554
555 #[test]
556 fn test_prelude_each_basic() {
557 let mut interp = setup_interpreter_with_prelude();
558
559 execute_string("[10 20 30] [drop] each", &mut interp).unwrap();
561
562 assert!(interp.pop().is_err());
564 }
565
566 #[test]
567 fn test_prelude_each_empty_list() {
568 let mut interp = setup_interpreter_with_prelude();
569
570 execute_string("42 [] [drop] each", &mut interp).unwrap();
572
573 let result = interp.pop().unwrap();
575 assert!(matches!(result, Value::Int32(42)));
576
577 assert!(interp.pop().is_err());
579 }
580
581 #[test]
582 fn test_prelude_each_with_print() {
583 let mut interp = setup_interpreter_with_prelude();
584
585 execute_string("[1 2 3] [.] each", &mut interp).unwrap();
588
589 assert!(interp.pop().is_err());
591 }
592
593 #[test]
594 fn test_prelude_not() {
595 let mut interp = setup_interpreter_with_prelude();
596
597 execute_string("true not", &mut interp).unwrap();
599 let result = interp.pop().unwrap();
600 assert!(matches!(result, Value::Boolean(false)));
601
602 execute_string("false not", &mut interp).unwrap();
604 let result = interp.pop().unwrap();
605 assert!(matches!(result, Value::Boolean(true)));
606
607 execute_string("42 not", &mut interp).unwrap();
609 let result = interp.pop().unwrap();
610 assert!(matches!(result, Value::Boolean(false)));
611
612 execute_string("0 not", &mut interp).unwrap();
614 let result = interp.pop().unwrap();
615 assert!(matches!(result, Value::Boolean(true)));
616
617 execute_string("null not", &mut interp).unwrap();
619 let result = interp.pop().unwrap();
620 assert!(matches!(result, Value::Boolean(true)));
621
622 execute_string("[1 2 3] not", &mut interp).unwrap();
624 let result = interp.pop().unwrap();
625 assert!(matches!(result, Value::Boolean(false)));
626
627 execute_string("5 not not", &mut interp).unwrap();
629 let result = interp.pop().unwrap();
630 assert!(matches!(result, Value::Boolean(true)));
631 }
632
633 #[test]
634 fn test_prelude_list_ref() {
635 let mut interp = setup_interpreter_with_prelude();
636
637 execute_string("[10 20 30 40] 0 list-ref", &mut interp).unwrap();
639 let result = interp.pop().unwrap();
640 assert!(matches!(result, Value::Int32(10)));
641
642 execute_string("[10 20 30 40] 1 list-ref", &mut interp).unwrap();
644 let result = interp.pop().unwrap();
645 assert!(matches!(result, Value::Int32(20)));
646
647 execute_string("[10 20 30 40] 3 list-ref", &mut interp).unwrap();
649 let result = interp.pop().unwrap();
650 assert!(matches!(result, Value::Int32(40)));
651
652 execute_string("[42] 0 list-ref", &mut interp).unwrap();
654 let result = interp.pop().unwrap();
655 assert!(matches!(result, Value::Int32(42)));
656
657 execute_string("[[1 2] [3 4] [5 6]] 2 list-ref 0 list-ref", &mut interp).unwrap();
659 let result = interp.pop().unwrap();
660 assert!(matches!(result, Value::Int32(5)));
661 }
662
663 #[test]
664 fn test_prelude_append() {
665 let mut interp = setup_interpreter_with_prelude();
666
667 execute_string("[1 2] [3 4] append", &mut interp).unwrap();
669 execute_string("dup length", &mut interp).unwrap();
670 let len = interp.pop().unwrap();
671 assert!(matches!(len, Value::Int32(4)));
672 execute_string("0 list-ref", &mut interp).unwrap();
674 assert!(matches!(interp.pop().unwrap(), Value::Int32(1)));
675
676 execute_string("[] [1 2 3] append", &mut interp).unwrap();
678 execute_string("length", &mut interp).unwrap();
679 let len = interp.pop().unwrap();
680 assert!(matches!(len, Value::Int32(3)));
681
682 execute_string("[1 2 3] [] append", &mut interp).unwrap();
684 execute_string("length", &mut interp).unwrap();
685 let len = interp.pop().unwrap();
686 assert!(matches!(len, Value::Int32(3)));
687
688 execute_string("[] [] append", &mut interp).unwrap();
690 let result = interp.pop().unwrap();
691 assert!(matches!(result, Value::Nil));
692
693 execute_string("[10] [20] append", &mut interp).unwrap();
695 execute_string("dup 0 list-ref swap 1 list-ref", &mut interp).unwrap();
696 let second = interp.pop().unwrap();
697 let first = interp.pop().unwrap();
698 assert!(matches!(first, Value::Int32(10)));
699 assert!(matches!(second, Value::Int32(20)));
700
701 execute_string("[1] [2 3] append [4 5] append", &mut interp).unwrap();
703 execute_string("length", &mut interp).unwrap();
704 let len = interp.pop().unwrap();
705 assert!(matches!(len, Value::Int32(5)));
706 }
707
708 #[test]
709 fn test_prelude_negate() {
710 let mut interp = setup_interpreter_with_prelude();
711
712 execute_string("5 negate", &mut interp).unwrap();
714 let result = interp.pop().unwrap();
715 assert!(matches!(result, Value::Int32(-5)));
716
717 execute_string("-3 negate", &mut interp).unwrap();
719 let result = interp.pop().unwrap();
720 assert!(matches!(result, Value::Int32(3)));
721
722 execute_string("0 negate", &mut interp).unwrap();
724 let result = interp.pop().unwrap();
725 assert!(matches!(result, Value::Int32(0)));
726
727 execute_string("7 negate negate", &mut interp).unwrap();
729 let result = interp.pop().unwrap();
730 assert!(matches!(result, Value::Int32(7)));
731
732 execute_string("3.14 negate", &mut interp).unwrap();
734 let result = interp.pop().unwrap();
735 match result {
736 Value::Number(f) => assert!((f - (-3.14)).abs() < 0.0001),
737 _ => panic!("Expected Number, got {:?}", result),
738 }
739
740 execute_string("3/4 negate", &mut interp).unwrap();
742 let result = interp.pop().unwrap();
743 match result {
745 Value::Rational(r) => {
746 assert_eq!(r.numer(), &num_bigint::BigInt::from(-3));
747 assert_eq!(r.denom(), &num_bigint::BigInt::from(4));
748 }
749 _ => panic!("Expected Rational, got {:?}", result),
750 }
751 }
752}