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 \\ Date/time operations
141 \\ Date record type with calendar components
142 \\ The 'now' primitive (written in Rust) returns instances of this record type
143 ["year" "month" "day" "hour" "minute" "second" "offset"] "date" make-record-type drop
144 "#;
145
146 execute_string(prelude_code, interp)?;
149
150 #[cfg(feature = "complex_numbers")]
153 {
154 let complex_prelude = r#"
155 \\ Mathematical constants (complex numbers)
156 'i 0+1i def
157 "Imaginary unit constant (0+1i)" doc
158 "#;
159 execute_string(complex_prelude, interp)?;
160 }
161
162 #[cfg(target_os = "none")]
165 {
166 let hardware_prelude = r#"
167 \\ Hardware convenience wrappers (micro:bit only)
168 'button-a? [0 button-read] def
169 "( -- bool ) Read button A state (true = pressed)" doc
170
171 'button-b? [1 button-read] def
172 "( -- bool ) Read button B state (true = pressed)" doc
173 "#;
174 execute_string(hardware_prelude, interp)?;
175 }
176
177 Ok(())
178}
179
180#[cfg(test)]
182mod tests {
183 use super::*;
184 use crate::value::Value;
185
186 fn setup_interpreter_with_prelude() -> Interpreter {
188 let mut interp = Interpreter::new();
191 load_prelude(&mut interp).unwrap();
192 interp
193 }
194
195 #[test]
196 fn test_prelude_dup() {
197 let mut interp = setup_interpreter_with_prelude();
198
199 execute_string("42 dup", &mut interp).unwrap();
201
202 let top = interp.pop().unwrap();
203 let second = interp.pop().unwrap();
204
205 assert!(matches!(top, Value::Int32(42)));
206 assert!(matches!(second, Value::Int32(42)));
207 }
208
209 #[test]
210 fn test_prelude_swap() {
211 let mut interp = setup_interpreter_with_prelude();
212
213 execute_string("1 2 swap", &mut interp).unwrap();
215
216 let top = interp.pop().unwrap();
217 let second = interp.pop().unwrap();
218
219 assert!(matches!(top, Value::Int32(1)));
220 assert!(matches!(second, Value::Int32(2)));
221 }
222
223 #[test]
224 fn test_prelude_over() {
225 let mut interp = setup_interpreter_with_prelude();
226
227 execute_string("1 2 over", &mut interp).unwrap();
229
230 let top = interp.pop().unwrap();
231 let second = interp.pop().unwrap();
232 let third = interp.pop().unwrap();
233
234 assert!(matches!(top, Value::Int32(1)));
235 assert!(matches!(second, Value::Int32(2)));
236 assert!(matches!(third, Value::Int32(1)));
237 }
238
239 #[test]
240 fn test_prelude_rot() {
241 let mut interp = setup_interpreter_with_prelude();
242
243 execute_string("1 2 3 rot", &mut interp).unwrap();
245
246 let top = interp.pop().unwrap();
247 let second = interp.pop().unwrap();
248 let third = interp.pop().unwrap();
249
250 assert!(matches!(top, Value::Int32(1)));
251 assert!(matches!(second, Value::Int32(3)));
252 assert!(matches!(third, Value::Int32(2)));
253 }
254
255 #[test]
256 fn test_prelude_nip() {
257 let mut interp = setup_interpreter_with_prelude();
258
259 execute_string("1 2 3 nip", &mut interp).unwrap();
261
262 let top = interp.pop().unwrap();
263 let second = interp.pop().unwrap();
264
265 assert!(matches!(top, Value::Int32(3)));
266 assert!(matches!(second, Value::Int32(1)));
267
268 assert!(interp.pop().is_err());
270 }
271
272 #[test]
273 fn test_prelude_tuck() {
274 let mut interp = setup_interpreter_with_prelude();
275
276 execute_string("5 6 tuck", &mut interp).unwrap();
278
279 let top = interp.pop().unwrap();
280 let second = interp.pop().unwrap();
281 let third = interp.pop().unwrap();
282
283 assert!(matches!(top, Value::Int32(6)));
284 assert!(matches!(second, Value::Int32(5)));
285 assert!(matches!(third, Value::Int32(6)));
286
287 assert!(interp.pop().is_err());
289 }
290
291 #[test]
292 fn test_prelude_length() {
293 let mut interp = setup_interpreter_with_prelude();
294
295 execute_string("[1 2 3 4 5] length", &mut interp).unwrap();
297
298 let result = interp.pop().unwrap();
299 assert!(matches!(result, Value::Int32(5)));
300
301 execute_string("[] length", &mut interp).unwrap();
303
304 let result = interp.pop().unwrap();
305 assert!(matches!(result, Value::Int32(0)));
306 }
307
308 #[test]
309 fn test_prelude_null_predicate() {
310 let mut interp = setup_interpreter_with_prelude();
311
312 execute_string("null null?", &mut interp).unwrap();
314
315 let result = interp.pop().unwrap();
316 assert!(matches!(result, Value::Boolean(true)));
317
318 execute_string("42 null?", &mut interp).unwrap();
320
321 let result = interp.pop().unwrap();
322 assert!(matches!(result, Value::Boolean(false)));
323
324 execute_string("[] null?", &mut interp).unwrap();
326
327 let result = interp.pop().unwrap();
328 assert!(matches!(result, Value::Boolean(false)));
329 }
330
331 #[test]
332 fn test_prelude_while_loop_counter() {
333 let mut interp = setup_interpreter_with_prelude();
334
335 let code = r#"
339 1
340 [ dup 5 < ]
341 [ 1 + ]
342 while
343 "#;
344
345 execute_string(code, &mut interp).unwrap();
346
347 let result = interp.pop().unwrap();
349 assert!(matches!(result, Value::Int32(5)));
350
351 assert!(interp.pop().is_err());
353 }
354
355 #[test]
356 fn test_prelude_while_sum_accumulator() {
357 let mut interp = setup_interpreter_with_prelude();
358
359 let code = r#"
362 1 0
363 [ over 5 <= ]
364 [ over + swap 1 + swap ]
365 while
366 nip
367 "#;
368
369 execute_string(code, &mut interp).unwrap();
370
371 let result = interp.pop().unwrap();
373 assert!(matches!(result, Value::Int32(15)));
374
375 assert!(interp.pop().is_err());
377 }
378
379 #[test]
380 fn test_prelude_while_empty_body() {
381 let mut interp = setup_interpreter_with_prelude();
382
383 let code = r#"
385 42
386 [ 0 ]
387 [ 99 ]
388 while
389 "#;
390
391 execute_string(code, &mut interp).unwrap();
392
393 let result = interp.pop().unwrap();
395 assert!(matches!(result, Value::Int32(42)));
396
397 assert!(interp.pop().is_err());
399 }
400
401 #[test]
402 fn test_prelude_question_dup() {
403 let mut interp = setup_interpreter_with_prelude();
404
405 execute_string("42 ?dup", &mut interp).unwrap();
407
408 let top = interp.pop().unwrap();
409 let second = interp.pop().unwrap();
410 assert!(matches!(top, Value::Int32(42)));
411 assert!(matches!(second, Value::Int32(42)));
412
413 execute_string("0 ?dup", &mut interp).unwrap();
415
416 let result = interp.pop().unwrap();
417 assert!(matches!(result, Value::Int32(0)));
418 assert!(interp.pop().is_err());
420
421 execute_string("false ?dup", &mut interp).unwrap();
423
424 let result = interp.pop().unwrap();
425 assert!(matches!(result, Value::Boolean(false)));
426 assert!(interp.pop().is_err());
427 }
428
429 #[test]
430 fn test_prelude_and_short_circuit() {
431 let mut interp = setup_interpreter_with_prelude();
432
433 execute_string("[5] [10] and", &mut interp).unwrap();
435
436 let result = interp.pop().unwrap();
437 assert!(matches!(result, Value::Int32(10)));
438
439 execute_string("[0] [99] and", &mut interp).unwrap();
441
442 let result = interp.pop().unwrap();
443 assert!(matches!(result, Value::Int32(0)));
444
445 execute_string("999 [0] [drop] and", &mut interp).unwrap();
449
450 let and_result = interp.pop().unwrap();
451 let marker = interp.pop().unwrap();
452 assert!(matches!(and_result, Value::Int32(0)));
453 assert!(matches!(marker, Value::Int32(999))); }
455
456 #[test]
457 fn test_prelude_or_short_circuit() {
458 let mut interp = setup_interpreter_with_prelude();
459
460 execute_string("[0] [42] or", &mut interp).unwrap();
462
463 let result = interp.pop().unwrap();
464 assert!(matches!(result, Value::Int32(42)));
465
466 execute_string("[5] [99] or", &mut interp).unwrap();
468
469 let result = interp.pop().unwrap();
470 assert!(matches!(result, Value::Int32(5)));
471
472 execute_string("888 [7] [drop] or", &mut interp).unwrap();
474
475 let or_result = interp.pop().unwrap();
476 let marker = interp.pop().unwrap();
477 assert!(matches!(or_result, Value::Int32(7)));
478 assert!(matches!(marker, Value::Int32(888))); }
480
481 #[test]
482 fn test_prelude_and_or_chaining() {
483 let mut interp = setup_interpreter_with_prelude();
484
485 execute_string("[1] [2] and [3] and", &mut interp).unwrap();
487
488 let result = interp.pop().unwrap();
489 assert!(matches!(result, Value::Int32(3)));
490
491 execute_string("[1] [2] or [3] or", &mut interp).unwrap();
493
494 let result = interp.pop().unwrap();
495 assert!(matches!(result, Value::Int32(1)));
496
497 execute_string("[0] [5] or [10] and", &mut interp).unwrap();
499
500 let result = interp.pop().unwrap();
501 assert!(matches!(result, Value::Int32(10)));
502 }
503
504 #[test]
505 #[cfg(feature = "complex_numbers")]
506 fn test_prelude_imaginary_constant() {
507 use num_bigint::BigInt;
508 let mut interp = setup_interpreter_with_prelude();
509
510 execute_string("i", &mut interp).unwrap();
512
513 let result = interp.pop().unwrap();
514 assert!(matches!(result, Value::GaussianInt(ref re, ref im)
515 if re == &BigInt::from(0) && im == &BigInt::from(1)));
516
517 execute_string("i i +", &mut interp).unwrap();
519
520 let result = interp.pop().unwrap();
521 assert!(matches!(result, Value::GaussianInt(ref re, ref im)
522 if re == &BigInt::from(0) && im == &BigInt::from(2)));
523 }
524
525 #[test]
526 fn test_prelude_each_basic() {
527 let mut interp = setup_interpreter_with_prelude();
528
529 execute_string("[10 20 30] [drop] each", &mut interp).unwrap();
531
532 assert!(interp.pop().is_err());
534 }
535
536 #[test]
537 fn test_prelude_each_empty_list() {
538 let mut interp = setup_interpreter_with_prelude();
539
540 execute_string("42 [] [drop] each", &mut interp).unwrap();
542
543 let result = interp.pop().unwrap();
545 assert!(matches!(result, Value::Int32(42)));
546
547 assert!(interp.pop().is_err());
549 }
550
551 #[test]
552 fn test_prelude_each_with_print() {
553 let mut interp = setup_interpreter_with_prelude();
554
555 execute_string("[1 2 3] [.] each", &mut interp).unwrap();
558
559 assert!(interp.pop().is_err());
561 }
562}