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 \\ Short-circuiting logical operations
62 'and [
63 swap \\ Move first quotation to top
64 exec \\ Execute first quotation
65 dup \\ Always duplicate the result
66 [
67 drop \\ Drop the duplicate, keep original
68 exec \\ Execute second quotation
69 ]
70 [
71 swap drop \\ If falsy, drop second quotation, keep falsy result
72 ]
73 if
74 ] def
75 "( [cond1] [cond2] -- result ) Short-circuit AND: executes cond2 only if cond1 is truthy" doc
76
77 'or [
78 swap \\ Move first quotation to top
79 exec \\ Execute first quotation
80 dup \\ Always duplicate the result
81 [
82 swap drop \\ If truthy, drop second quotation, keep result
83 ]
84 [
85 drop \\ Drop the duplicate
86 exec \\ If falsy, execute second quotation
87 ]
88 if
89 ] def
90 "( [cond1] [cond2] -- result ) Short-circuit OR: executes cond2 only if cond1 is falsy" doc
91
92 \\ Control flow primitives
93 'while [
94 >r >r \\ move body and condition to return stack
95 r@ exec \\ execute condition (copy from R-stack)
96 [
97 r> r> dup rot swap >r >r \\ get body and move body and condition back to return stack
98 exec \\ execute body
99 r> r> while \\ recursive call
100 ]
101 [ r> r> drop drop ]
102 if
103 ] def
104 "( [condition] [body] -- ) Loop: executes body while condition returns truthy" doc
105 "#;
106
107 execute_string(prelude_code, interp)?;
110
111 #[cfg(feature = "complex_numbers")]
114 {
115 let complex_prelude = r#"
116 \\ Mathematical constants (complex numbers)
117 'i 0+1i def
118 "Imaginary unit constant (0+1i)" doc
119 "#;
120 execute_string(complex_prelude, interp)?;
121 }
122
123 #[cfg(target_os = "none")]
126 {
127 let hardware_prelude = r#"
128 \\ Hardware convenience wrappers (micro:bit only)
129 'button-a? [0 button-read] def
130 "( -- bool ) Read button A state (true = pressed)" doc
131
132 'button-b? [1 button-read] def
133 "( -- bool ) Read button B state (true = pressed)" doc
134 "#;
135 execute_string(hardware_prelude, interp)?;
136 }
137
138 Ok(())
139}
140
141#[cfg(test)]
143mod tests {
144 use super::*;
145 use crate::value::Value;
146
147 fn setup_interpreter_with_prelude() -> Interpreter {
149 let mut interp = Interpreter::new();
152 load_prelude(&mut interp).unwrap();
153 interp
154 }
155
156 #[test]
157 fn test_prelude_dup() {
158 let mut interp = setup_interpreter_with_prelude();
159
160 execute_string("42 dup", &mut interp).unwrap();
162
163 let top = interp.pop().unwrap();
164 let second = interp.pop().unwrap();
165
166 assert!(matches!(top, Value::Int32(42)));
167 assert!(matches!(second, Value::Int32(42)));
168 }
169
170 #[test]
171 fn test_prelude_swap() {
172 let mut interp = setup_interpreter_with_prelude();
173
174 execute_string("1 2 swap", &mut interp).unwrap();
176
177 let top = interp.pop().unwrap();
178 let second = interp.pop().unwrap();
179
180 assert!(matches!(top, Value::Int32(1)));
181 assert!(matches!(second, Value::Int32(2)));
182 }
183
184 #[test]
185 fn test_prelude_over() {
186 let mut interp = setup_interpreter_with_prelude();
187
188 execute_string("1 2 over", &mut interp).unwrap();
190
191 let top = interp.pop().unwrap();
192 let second = interp.pop().unwrap();
193 let third = interp.pop().unwrap();
194
195 assert!(matches!(top, Value::Int32(1)));
196 assert!(matches!(second, Value::Int32(2)));
197 assert!(matches!(third, Value::Int32(1)));
198 }
199
200 #[test]
201 fn test_prelude_rot() {
202 let mut interp = setup_interpreter_with_prelude();
203
204 execute_string("1 2 3 rot", &mut interp).unwrap();
206
207 let top = interp.pop().unwrap();
208 let second = interp.pop().unwrap();
209 let third = interp.pop().unwrap();
210
211 assert!(matches!(top, Value::Int32(1)));
212 assert!(matches!(second, Value::Int32(3)));
213 assert!(matches!(third, Value::Int32(2)));
214 }
215
216 #[test]
217 fn test_prelude_nip() {
218 let mut interp = setup_interpreter_with_prelude();
219
220 execute_string("1 2 3 nip", &mut interp).unwrap();
222
223 let top = interp.pop().unwrap();
224 let second = interp.pop().unwrap();
225
226 assert!(matches!(top, Value::Int32(3)));
227 assert!(matches!(second, Value::Int32(1)));
228
229 assert!(interp.pop().is_err());
231 }
232
233 #[test]
234 fn test_prelude_tuck() {
235 let mut interp = setup_interpreter_with_prelude();
236
237 execute_string("5 6 tuck", &mut interp).unwrap();
239
240 let top = interp.pop().unwrap();
241 let second = interp.pop().unwrap();
242 let third = interp.pop().unwrap();
243
244 assert!(matches!(top, Value::Int32(6)));
245 assert!(matches!(second, Value::Int32(5)));
246 assert!(matches!(third, Value::Int32(6)));
247
248 assert!(interp.pop().is_err());
250 }
251
252 #[test]
253 fn test_prelude_length() {
254 let mut interp = setup_interpreter_with_prelude();
255
256 execute_string("[1 2 3 4 5] length", &mut interp).unwrap();
258
259 let result = interp.pop().unwrap();
260 assert!(matches!(result, Value::Int32(5)));
261
262 execute_string("[] length", &mut interp).unwrap();
264
265 let result = interp.pop().unwrap();
266 assert!(matches!(result, Value::Int32(0)));
267 }
268
269 #[test]
270 fn test_prelude_null_predicate() {
271 let mut interp = setup_interpreter_with_prelude();
272
273 execute_string("null null?", &mut interp).unwrap();
275
276 let result = interp.pop().unwrap();
277 assert!(matches!(result, Value::Boolean(true)));
278
279 execute_string("42 null?", &mut interp).unwrap();
281
282 let result = interp.pop().unwrap();
283 assert!(matches!(result, Value::Boolean(false)));
284
285 execute_string("[] null?", &mut interp).unwrap();
287
288 let result = interp.pop().unwrap();
289 assert!(matches!(result, Value::Boolean(false)));
290 }
291
292 #[test]
293 fn test_prelude_while_loop_counter() {
294 let mut interp = setup_interpreter_with_prelude();
295
296 let code = r#"
300 1
301 [ dup 5 < ]
302 [ 1 + ]
303 while
304 "#;
305
306 execute_string(code, &mut interp).unwrap();
307
308 let result = interp.pop().unwrap();
310 assert!(matches!(result, Value::Int32(5)));
311
312 assert!(interp.pop().is_err());
314 }
315
316 #[test]
317 fn test_prelude_while_sum_accumulator() {
318 let mut interp = setup_interpreter_with_prelude();
319
320 let code = r#"
323 1 0
324 [ over 5 <= ]
325 [ over + swap 1 + swap ]
326 while
327 nip
328 "#;
329
330 execute_string(code, &mut interp).unwrap();
331
332 let result = interp.pop().unwrap();
334 assert!(matches!(result, Value::Int32(15)));
335
336 assert!(interp.pop().is_err());
338 }
339
340 #[test]
341 fn test_prelude_while_empty_body() {
342 let mut interp = setup_interpreter_with_prelude();
343
344 let code = r#"
346 42
347 [ 0 ]
348 [ 99 ]
349 while
350 "#;
351
352 execute_string(code, &mut interp).unwrap();
353
354 let result = interp.pop().unwrap();
356 assert!(matches!(result, Value::Int32(42)));
357
358 assert!(interp.pop().is_err());
360 }
361
362 #[test]
363 fn test_prelude_question_dup() {
364 let mut interp = setup_interpreter_with_prelude();
365
366 execute_string("42 ?dup", &mut interp).unwrap();
368
369 let top = interp.pop().unwrap();
370 let second = interp.pop().unwrap();
371 assert!(matches!(top, Value::Int32(42)));
372 assert!(matches!(second, Value::Int32(42)));
373
374 execute_string("0 ?dup", &mut interp).unwrap();
376
377 let result = interp.pop().unwrap();
378 assert!(matches!(result, Value::Int32(0)));
379 assert!(interp.pop().is_err());
381
382 execute_string("false ?dup", &mut interp).unwrap();
384
385 let result = interp.pop().unwrap();
386 assert!(matches!(result, Value::Boolean(false)));
387 assert!(interp.pop().is_err());
388 }
389
390 #[test]
391 fn test_prelude_and_short_circuit() {
392 let mut interp = setup_interpreter_with_prelude();
393
394 execute_string("[5] [10] and", &mut interp).unwrap();
396
397 let result = interp.pop().unwrap();
398 assert!(matches!(result, Value::Int32(10)));
399
400 execute_string("[0] [99] and", &mut interp).unwrap();
402
403 let result = interp.pop().unwrap();
404 assert!(matches!(result, Value::Int32(0)));
405
406 execute_string("999 [0] [drop] and", &mut interp).unwrap();
410
411 let and_result = interp.pop().unwrap();
412 let marker = interp.pop().unwrap();
413 assert!(matches!(and_result, Value::Int32(0)));
414 assert!(matches!(marker, Value::Int32(999))); }
416
417 #[test]
418 fn test_prelude_or_short_circuit() {
419 let mut interp = setup_interpreter_with_prelude();
420
421 execute_string("[0] [42] or", &mut interp).unwrap();
423
424 let result = interp.pop().unwrap();
425 assert!(matches!(result, Value::Int32(42)));
426
427 execute_string("[5] [99] or", &mut interp).unwrap();
429
430 let result = interp.pop().unwrap();
431 assert!(matches!(result, Value::Int32(5)));
432
433 execute_string("888 [7] [drop] or", &mut interp).unwrap();
435
436 let or_result = interp.pop().unwrap();
437 let marker = interp.pop().unwrap();
438 assert!(matches!(or_result, Value::Int32(7)));
439 assert!(matches!(marker, Value::Int32(888))); }
441
442 #[test]
443 fn test_prelude_and_or_chaining() {
444 let mut interp = setup_interpreter_with_prelude();
445
446 execute_string("[1] [2] and [3] and", &mut interp).unwrap();
448
449 let result = interp.pop().unwrap();
450 assert!(matches!(result, Value::Int32(3)));
451
452 execute_string("[1] [2] or [3] or", &mut interp).unwrap();
454
455 let result = interp.pop().unwrap();
456 assert!(matches!(result, Value::Int32(1)));
457
458 execute_string("[0] [5] or [10] and", &mut interp).unwrap();
460
461 let result = interp.pop().unwrap();
462 assert!(matches!(result, Value::Int32(10)));
463 }
464
465 #[test]
466 #[cfg(feature = "complex_numbers")]
467 fn test_prelude_imaginary_constant() {
468 use num_bigint::BigInt;
469 let mut interp = setup_interpreter_with_prelude();
470
471 execute_string("i", &mut interp).unwrap();
473
474 let result = interp.pop().unwrap();
475 assert!(matches!(result, Value::GaussianInt(ref re, ref im)
476 if re == &BigInt::from(0) && im == &BigInt::from(1)));
477
478 execute_string("i i +", &mut interp).unwrap();
480
481 let result = interp.pop().unwrap();
482 assert!(matches!(result, Value::GaussianInt(ref re, ref im)
483 if re == &BigInt::from(0) && im == &BigInt::from(2)));
484 }
485}