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 \\ List processing primitives
41 'length [
42 dup nil?
43 [drop 0]
44 [tail length 1 +]
45 if
46 ] def
47 "( list -- n ) Calculate list length recursively" doc
48
49 'null? [null =] def
50 "( x -- bool ) Test if value is null" doc
51
52 'record? [type "record" =] def
53 "( x -- bool ) Test if value is any record type" doc
54
55 \\ Conditional duplication from Forth
56 '?dup [
57 dup truthy? [dup] [] if
58 ] def
59 "( x -- x x | x ) Duplicate if truthy, otherwise leave unchanged" doc
60
61 \\ Variable operations (Forth-style)
62 '1+ [1 +] def
63 "( n -- n+1 ) Increment by 1" doc
64
65 '1- [1 -] def
66 "( n -- n-1 ) Decrement by 1" doc
67
68 '+! [dup @ rot + swap !] def
69 "( n var -- ) Add n to variable" doc
70
71 'on [true swap !] def
72 "( var -- ) Store true to variable" doc
73
74 'off [false swap !] def
75 "( var -- ) Store false to variable" doc
76
77 \\ List iteration
78 'each [
79 >r \\ Move fn to return stack: list | fn
80 dup nil? \\ Check if list is empty: list bool | fn
81 [
82 drop r> drop \\ Empty list: clean up list and fn
83 ]
84 [
85 dup head \\ list -> list head | fn
86 r@ \\ Get fn: list head fn | fn
87 exec \\ Execute fn: list ... | fn (fn consumes head, may leave results)
88 tail \\ Get tail: ... tail | fn
89 r> each \\ Recurse: ... tail fn
90 ]
91 if
92 ] def
93 "( list [fn] -- ) Execute fn on each element of list (fn consumes argument, may leave results)" doc
94
95 \\ Short-circuiting logical operations
96 'and [
97 swap \\ Move first quotation to top
98 exec \\ Execute first quotation
99 dup \\ Always duplicate the result
100 [
101 drop \\ Drop the duplicate, keep original
102 exec \\ Execute second quotation
103 ]
104 [
105 swap drop \\ If falsy, drop second quotation, keep falsy result
106 ]
107 if
108 ] def
109 "( [cond1] [cond2] -- result ) Short-circuit AND: executes cond2 only if cond1 is truthy" doc
110
111 'or [
112 swap \\ Move first quotation to top
113 exec \\ Execute first quotation
114 dup \\ Always duplicate the result
115 [
116 swap drop \\ If truthy, drop second quotation, keep result
117 ]
118 [
119 drop \\ Drop the duplicate
120 exec \\ If falsy, execute second quotation
121 ]
122 if
123 ] def
124 "( [cond1] [cond2] -- result ) Short-circuit OR: executes cond2 only if cond1 is falsy" doc
125
126 \\ Control flow primitives
127 'while [
128 >r >r \\ move body and condition to return stack
129 r@ exec \\ execute condition (copy from R-stack)
130 [
131 r> r> dup rot swap >r >r \\ get body and move body and condition back to return stack
132 exec \\ execute body
133 r> r> while \\ recursive call
134 ]
135 [ r> r> drop drop ]
136 if
137 ] def
138 "( [condition] [body] -- ) Loop: executes body while condition returns truthy" doc
139 "#;
140
141 execute_string(prelude_code, interp)?;
144
145 #[cfg(feature = "complex_numbers")]
148 {
149 let complex_prelude = r#"
150 \\ Mathematical constants (complex numbers)
151 'i 0+1i def
152 "Imaginary unit constant (0+1i)" doc
153 "#;
154 execute_string(complex_prelude, interp)?;
155 }
156
157 #[cfg(target_os = "none")]
160 {
161 let hardware_prelude = r#"
162 \\ Hardware convenience wrappers (micro:bit only)
163 'button-a? [0 button-read] def
164 "( -- bool ) Read button A state (true = pressed)" doc
165
166 'button-b? [1 button-read] def
167 "( -- bool ) Read button B state (true = pressed)" doc
168 "#;
169 execute_string(hardware_prelude, interp)?;
170 }
171
172 Ok(())
173}
174
175#[cfg(test)]
177mod tests {
178 use super::*;
179 use crate::value::Value;
180
181 fn setup_interpreter_with_prelude() -> Interpreter {
183 let mut interp = Interpreter::new();
186 load_prelude(&mut interp).unwrap();
187 interp
188 }
189
190 #[test]
191 fn test_prelude_dup() {
192 let mut interp = setup_interpreter_with_prelude();
193
194 execute_string("42 dup", &mut interp).unwrap();
196
197 let top = interp.pop().unwrap();
198 let second = interp.pop().unwrap();
199
200 assert!(matches!(top, Value::Int32(42)));
201 assert!(matches!(second, Value::Int32(42)));
202 }
203
204 #[test]
205 fn test_prelude_swap() {
206 let mut interp = setup_interpreter_with_prelude();
207
208 execute_string("1 2 swap", &mut interp).unwrap();
210
211 let top = interp.pop().unwrap();
212 let second = interp.pop().unwrap();
213
214 assert!(matches!(top, Value::Int32(1)));
215 assert!(matches!(second, Value::Int32(2)));
216 }
217
218 #[test]
219 fn test_prelude_over() {
220 let mut interp = setup_interpreter_with_prelude();
221
222 execute_string("1 2 over", &mut interp).unwrap();
224
225 let top = interp.pop().unwrap();
226 let second = interp.pop().unwrap();
227 let third = interp.pop().unwrap();
228
229 assert!(matches!(top, Value::Int32(1)));
230 assert!(matches!(second, Value::Int32(2)));
231 assert!(matches!(third, Value::Int32(1)));
232 }
233
234 #[test]
235 fn test_prelude_rot() {
236 let mut interp = setup_interpreter_with_prelude();
237
238 execute_string("1 2 3 rot", &mut interp).unwrap();
240
241 let top = interp.pop().unwrap();
242 let second = interp.pop().unwrap();
243 let third = interp.pop().unwrap();
244
245 assert!(matches!(top, Value::Int32(1)));
246 assert!(matches!(second, Value::Int32(3)));
247 assert!(matches!(third, Value::Int32(2)));
248 }
249
250 #[test]
251 fn test_prelude_nip() {
252 let mut interp = setup_interpreter_with_prelude();
253
254 execute_string("1 2 3 nip", &mut interp).unwrap();
256
257 let top = interp.pop().unwrap();
258 let second = interp.pop().unwrap();
259
260 assert!(matches!(top, Value::Int32(3)));
261 assert!(matches!(second, Value::Int32(1)));
262
263 assert!(interp.pop().is_err());
265 }
266
267 #[test]
268 fn test_prelude_tuck() {
269 let mut interp = setup_interpreter_with_prelude();
270
271 execute_string("5 6 tuck", &mut interp).unwrap();
273
274 let top = interp.pop().unwrap();
275 let second = interp.pop().unwrap();
276 let third = interp.pop().unwrap();
277
278 assert!(matches!(top, Value::Int32(6)));
279 assert!(matches!(second, Value::Int32(5)));
280 assert!(matches!(third, Value::Int32(6)));
281
282 assert!(interp.pop().is_err());
284 }
285
286 #[test]
287 fn test_prelude_length() {
288 let mut interp = setup_interpreter_with_prelude();
289
290 execute_string("[1 2 3 4 5] length", &mut interp).unwrap();
292
293 let result = interp.pop().unwrap();
294 assert!(matches!(result, Value::Int32(5)));
295
296 execute_string("[] length", &mut interp).unwrap();
298
299 let result = interp.pop().unwrap();
300 assert!(matches!(result, Value::Int32(0)));
301 }
302
303 #[test]
304 fn test_prelude_null_predicate() {
305 let mut interp = setup_interpreter_with_prelude();
306
307 execute_string("null null?", &mut interp).unwrap();
309
310 let result = interp.pop().unwrap();
311 assert!(matches!(result, Value::Boolean(true)));
312
313 execute_string("42 null?", &mut interp).unwrap();
315
316 let result = interp.pop().unwrap();
317 assert!(matches!(result, Value::Boolean(false)));
318
319 execute_string("[] null?", &mut interp).unwrap();
321
322 let result = interp.pop().unwrap();
323 assert!(matches!(result, Value::Boolean(false)));
324 }
325
326 #[test]
327 fn test_prelude_while_loop_counter() {
328 let mut interp = setup_interpreter_with_prelude();
329
330 let code = r#"
334 1
335 [ dup 5 < ]
336 [ 1 + ]
337 while
338 "#;
339
340 execute_string(code, &mut interp).unwrap();
341
342 let result = interp.pop().unwrap();
344 assert!(matches!(result, Value::Int32(5)));
345
346 assert!(interp.pop().is_err());
348 }
349
350 #[test]
351 fn test_prelude_while_sum_accumulator() {
352 let mut interp = setup_interpreter_with_prelude();
353
354 let code = r#"
357 1 0
358 [ over 5 <= ]
359 [ over + swap 1 + swap ]
360 while
361 nip
362 "#;
363
364 execute_string(code, &mut interp).unwrap();
365
366 let result = interp.pop().unwrap();
368 assert!(matches!(result, Value::Int32(15)));
369
370 assert!(interp.pop().is_err());
372 }
373
374 #[test]
375 fn test_prelude_while_empty_body() {
376 let mut interp = setup_interpreter_with_prelude();
377
378 let code = r#"
380 42
381 [ 0 ]
382 [ 99 ]
383 while
384 "#;
385
386 execute_string(code, &mut interp).unwrap();
387
388 let result = interp.pop().unwrap();
390 assert!(matches!(result, Value::Int32(42)));
391
392 assert!(interp.pop().is_err());
394 }
395
396 #[test]
397 fn test_prelude_question_dup() {
398 let mut interp = setup_interpreter_with_prelude();
399
400 execute_string("42 ?dup", &mut interp).unwrap();
402
403 let top = interp.pop().unwrap();
404 let second = interp.pop().unwrap();
405 assert!(matches!(top, Value::Int32(42)));
406 assert!(matches!(second, Value::Int32(42)));
407
408 execute_string("0 ?dup", &mut interp).unwrap();
410
411 let result = interp.pop().unwrap();
412 assert!(matches!(result, Value::Int32(0)));
413 assert!(interp.pop().is_err());
415
416 execute_string("false ?dup", &mut interp).unwrap();
418
419 let result = interp.pop().unwrap();
420 assert!(matches!(result, Value::Boolean(false)));
421 assert!(interp.pop().is_err());
422 }
423
424 #[test]
425 fn test_prelude_and_short_circuit() {
426 let mut interp = setup_interpreter_with_prelude();
427
428 execute_string("[5] [10] and", &mut interp).unwrap();
430
431 let result = interp.pop().unwrap();
432 assert!(matches!(result, Value::Int32(10)));
433
434 execute_string("[0] [99] and", &mut interp).unwrap();
436
437 let result = interp.pop().unwrap();
438 assert!(matches!(result, Value::Int32(0)));
439
440 execute_string("999 [0] [drop] and", &mut interp).unwrap();
444
445 let and_result = interp.pop().unwrap();
446 let marker = interp.pop().unwrap();
447 assert!(matches!(and_result, Value::Int32(0)));
448 assert!(matches!(marker, Value::Int32(999))); }
450
451 #[test]
452 fn test_prelude_or_short_circuit() {
453 let mut interp = setup_interpreter_with_prelude();
454
455 execute_string("[0] [42] or", &mut interp).unwrap();
457
458 let result = interp.pop().unwrap();
459 assert!(matches!(result, Value::Int32(42)));
460
461 execute_string("[5] [99] or", &mut interp).unwrap();
463
464 let result = interp.pop().unwrap();
465 assert!(matches!(result, Value::Int32(5)));
466
467 execute_string("888 [7] [drop] or", &mut interp).unwrap();
469
470 let or_result = interp.pop().unwrap();
471 let marker = interp.pop().unwrap();
472 assert!(matches!(or_result, Value::Int32(7)));
473 assert!(matches!(marker, Value::Int32(888))); }
475
476 #[test]
477 fn test_prelude_and_or_chaining() {
478 let mut interp = setup_interpreter_with_prelude();
479
480 execute_string("[1] [2] and [3] and", &mut interp).unwrap();
482
483 let result = interp.pop().unwrap();
484 assert!(matches!(result, Value::Int32(3)));
485
486 execute_string("[1] [2] or [3] or", &mut interp).unwrap();
488
489 let result = interp.pop().unwrap();
490 assert!(matches!(result, Value::Int32(1)));
491
492 execute_string("[0] [5] or [10] and", &mut interp).unwrap();
494
495 let result = interp.pop().unwrap();
496 assert!(matches!(result, Value::Int32(10)));
497 }
498
499 #[test]
500 #[cfg(feature = "complex_numbers")]
501 fn test_prelude_imaginary_constant() {
502 use num_bigint::BigInt;
503 let mut interp = setup_interpreter_with_prelude();
504
505 execute_string("i", &mut interp).unwrap();
507
508 let result = interp.pop().unwrap();
509 assert!(matches!(result, Value::GaussianInt(ref re, ref im)
510 if re == &BigInt::from(0) && im == &BigInt::from(1)));
511
512 execute_string("i i +", &mut interp).unwrap();
514
515 let result = interp.pop().unwrap();
516 assert!(matches!(result, Value::GaussianInt(ref re, ref im)
517 if re == &BigInt::from(0) && im == &BigInt::from(2)));
518 }
519
520 #[test]
521 fn test_prelude_each_basic() {
522 let mut interp = setup_interpreter_with_prelude();
523
524 execute_string("[10 20 30] [drop] each", &mut interp).unwrap();
526
527 assert!(interp.pop().is_err());
529 }
530
531 #[test]
532 fn test_prelude_each_empty_list() {
533 let mut interp = setup_interpreter_with_prelude();
534
535 execute_string("42 [] [drop] each", &mut interp).unwrap();
537
538 let result = interp.pop().unwrap();
540 assert!(matches!(result, Value::Int32(42)));
541
542 assert!(interp.pop().is_err());
544 }
545
546 #[test]
547 fn test_prelude_each_with_print() {
548 let mut interp = setup_interpreter_with_prelude();
549
550 execute_string("[1 2 3] [.] each", &mut interp).unwrap();
553
554 assert!(interp.pop().is_err());
556 }
557}