1use crate::interpreter::Interpreter;
16use crate::value::{RuntimeError, Value};
17use crate::compat::{Rc, Vec, ToString};
18
19#[cfg(not(target_os = "none"))]
20use std::collections::HashMap;
21
22#[cfg(target_os = "none")]
23use alloc::collections::BTreeMap as HashMap;
24
25#[derive(Debug, Clone)]
29enum Continuation {
30 Value(Value),
32
33 List {
36 items: Vec<Value>,
37 index: usize,
38 },
39
40 If {
42 condition_result: bool,
43 true_branch: Value,
44 false_branch: Value,
45 },
46
47 Exec(Value),
49
50 Definition(Value),
52
53 PopLocalFrame,
56}
57
58pub fn execute_with_continuations(
61 initial_value: &Value,
62 interp: &mut Interpreter,
63) -> Result<(), RuntimeError> {
64 let mut continuation_stack: Vec<Continuation> = Vec::new();
65 continuation_stack.push(Continuation::Value(initial_value.clone()));
66
67 while let Some(continuation) = continuation_stack.pop() {
68 match continuation {
69 Continuation::Value(value) => {
70 execute_value_direct(&value, interp, &mut continuation_stack)?;
71 }
72
73 Continuation::List { items, index } => {
74 if index >= items.len() {
75 continue; }
77
78 let item = &items[index];
79 let is_tail_call = index == items.len() - 1;
80
81 if is_tail_call {
82 continuation_stack.push(Continuation::Value(item.clone()));
85 } else {
86 continuation_stack.push(Continuation::List {
88 items: items.clone(),
89 index: index + 1,
90 });
91 continuation_stack.push(Continuation::Value(item.clone()));
92 }
93 }
94
95 Continuation::If {
96 condition_result,
97 true_branch,
98 false_branch,
99 } => {
100 let branch = if condition_result {
101 true_branch
102 } else {
103 false_branch
104 };
105 match &branch {
107 Value::Pair(_, _) | Value::Nil => {
108 let items = list_to_vec(&branch)?;
109 continuation_stack.push(Continuation::List { items, index: 0 });
110 }
111 _ => {
112 continuation_stack.push(Continuation::Value(branch));
113 }
114 }
115 }
116
117 Continuation::Exec(value) => {
118 match &value {
120 Value::Pair(_, _) => {
121 interp.local_frames.push(HashMap::new());
123 continuation_stack.push(Continuation::PopLocalFrame);
125 let items = list_to_vec(&value)?;
127 continuation_stack.push(Continuation::List { items, index: 0 });
128 }
129 Value::Nil => {
130 }
132 _ => {
133 continuation_stack.push(Continuation::Value(value));
135 }
136 }
137 }
138
139 Continuation::Definition(definition) => {
140 match &definition {
141 Value::Pair(_, _) | Value::Nil => {
142 interp.local_frames.push(HashMap::new());
144 continuation_stack.push(Continuation::PopLocalFrame);
146 let items = list_to_vec(&definition)?;
148 continuation_stack.push(Continuation::List { items, index: 0 });
149 }
150 _ => {
151 continuation_stack.push(Continuation::Value(definition));
153 }
154 }
155 }
156
157 Continuation::PopLocalFrame => {
158 if interp.local_frames.is_empty() {
160 return Err(RuntimeError::TypeError(
161 "PopLocalFrame: no local frame to pop (internal error)".to_string(),
162 ));
163 }
164 interp.local_frames.pop();
165 }
166 }
167 }
168
169 Ok(())
170}
171
172fn execute_value_direct(
175 value: &Value,
176 interp: &mut Interpreter,
177 continuation_stack: &mut Vec<Continuation>,
178) -> Result<(), RuntimeError> {
179 match value {
180 Value::Number(n) => {
182 interp.push(Value::Number(*n));
183 Ok(())
184 }
185 Value::Int32(i) => {
187 interp.push(Value::Int32(*i));
188 Ok(())
189 }
190 Value::Integer(i) => {
191 interp.push(Value::Integer(i.clone()));
192 Ok(())
193 }
194 Value::Rational(r) => {
195 interp.push(Value::Rational(r.clone()));
196 Ok(())
197 }
198 #[cfg(feature = "complex_numbers")]
199 Value::Complex(c) => {
200 interp.push(Value::Complex(*c));
201 Ok(())
202 }
203 #[cfg(feature = "complex_numbers")]
204 Value::GaussianInt(re, im) => {
205 interp.push(Value::GaussianInt(re.clone(), im.clone()));
206 Ok(())
207 }
208 Value::String(s) => {
209 interp.push(Value::String(s.clone()));
210 Ok(())
211 }
212 Value::Boolean(b) => {
213 interp.push(Value::Boolean(*b));
214 Ok(())
215 }
216 Value::Null => {
217 interp.push(Value::Null);
218 Ok(())
219 }
220 Value::Array(array) => {
221 interp.push(Value::Array(array.clone()));
222 Ok(())
223 }
224 Value::Variable(var) => {
225 interp.push(Value::Variable(var.clone()));
226 Ok(())
227 }
228 Value::Pair(_, _) | Value::Nil => {
229 interp.push(value.clone());
230 Ok(())
231 }
232 Value::QuotedAtom(atom_name) => {
233 interp.push(Value::Atom(atom_name.clone()));
234 Ok(())
235 }
236 Value::Builtin(func) => func(interp),
237 Value::Atom(atom_name) => {
238 execute_atom_with_continuations(atom_name, interp, continuation_stack)
239 }
240 Value::Record { .. } | Value::RecordType { .. } => {
242 interp.push(value.clone());
243 Ok(())
244 }
245 Value::I16Buffer(_) => {
247 interp.push(value.clone());
248 Ok(())
249 }
250 }
251}
252
253fn list_to_vec(list: &Value) -> Result<Vec<Value>, RuntimeError> {
255 let mut current = list.clone();
256 let mut items = Vec::new();
257
258 loop {
259 match current {
260 Value::Pair(car, cdr) => {
261 items.push((*car).clone());
262 current = (*cdr).clone();
263 }
264 Value::Nil => break,
265 _ => {
266 items.push(current);
268 break;
269 }
270 }
271 }
272
273 Ok(items)
274}
275
276fn execute_atom_with_continuations(
278 atom_name: &Rc<str>,
279 interp: &mut Interpreter,
280 continuation_stack: &mut Vec<Continuation>,
281) -> Result<(), RuntimeError> {
282 if &**atom_name == "exec" {
284 let value = interp.pop()?;
285 continuation_stack.push(Continuation::Exec(value));
286 return Ok(());
287 }
288
289 if &**atom_name == "if" {
290 let false_branch = interp.pop()?;
291 let true_branch = interp.pop()?;
292 let condition = interp.pop()?;
293
294 let condition_result = interp.is_truthy(&condition);
295 continuation_stack.push(Continuation::If {
296 condition_result,
297 true_branch,
298 false_branch,
299 });
300 return Ok(());
301 }
302
303 if &**atom_name == "quit" {
304 return Err(RuntimeError::QuitRequested);
306 }
307
308 for frame in interp.local_frames.iter().rev() {
311 if let Some(value) = frame.get(atom_name) {
312 interp.push(value.clone());
314 return Ok(());
315 }
316 }
317
318 match interp.dictionary.get(atom_name) {
320 Some(entry) => {
321 let entry_copy = entry.clone();
322
323 if entry_copy.is_executable {
324 continuation_stack.push(Continuation::Definition(entry_copy.value));
326 } else {
327 interp.push(entry_copy.value);
329 }
330 Ok(())
331 }
332 None => Err(RuntimeError::UndefinedWord((**atom_name).to_string())),
333 }
334}
335
336pub fn execute(value: &Value, interp: &mut Interpreter) -> Result<(), RuntimeError> {
340 execute_with_continuations(value, interp)
341}
342
343pub fn execute_string(code: &str, interp: &mut Interpreter) -> Result<(), RuntimeError> {
348 use crate::parser::parse;
351
352 let values = parse(code, interp)?;
356
357 for value in values {
361 execute(&value, interp)?;
362 }
363
364 Ok(())
365}
366
367#[cfg(test)]
369mod tests {
370 use super::*;
371 fn setup_interpreter() -> Interpreter {
376 Interpreter::new()
379 }
380
381 #[test]
382 fn test_execute_numbers() {
383 let mut interp = setup_interpreter();
384
385 let number = Value::Number(42.0);
387 execute(&number, &mut interp).unwrap();
388
389 let result = interp.pop().unwrap();
391 assert!(matches!(result, Value::Number(n) if n == 42.0));
392 }
393
394 #[test]
395 fn test_execute_strings() {
396 let mut interp = setup_interpreter();
397
398 let string_val: Rc<str> = "hello world".into();
399 let string = Value::String(string_val);
400 execute(&string, &mut interp).unwrap();
401
402 let result = interp.pop().unwrap();
403 assert!(matches!(result, Value::String(s) if s.as_ref() == "hello world"));
404 }
405
406 #[test]
407 fn test_execute_lists_as_data() {
408 let mut interp = setup_interpreter();
409
410 let plus_atom = interp.intern_atom("+");
412 let list = interp.make_list(vec![
413 Value::Number(1.0),
414 Value::Number(2.0),
415 Value::Atom(plus_atom),
416 ]);
417
418 execute(&list, &mut interp).unwrap();
419
420 let result = interp.pop().unwrap();
422 assert!(matches!(result, Value::Pair(_, _)));
423
424 assert!(interp.pop().is_err());
426 }
427
428 #[test]
429 fn test_execute_builtin_functions() {
430 let mut interp = setup_interpreter();
431
432 interp.push(Value::Number(3.0));
435 interp.push(Value::Number(5.0));
436
437 let plus_atom = interp.intern_atom("+");
439 execute(&Value::Atom(plus_atom), &mut interp).unwrap();
440
441 let result = interp.pop().unwrap();
443 assert!(matches!(result, Value::Number(n) if n == 8.0));
444 }
445
446 #[test]
447 fn test_execute_undefined_atom() {
448 let mut interp = setup_interpreter();
449
450 let undefined_atom = interp.intern_atom("nonexistent");
452 let result = execute(&Value::Atom(undefined_atom), &mut interp);
453
454 assert!(result.is_err());
455 assert!(
456 matches!(result.unwrap_err(), RuntimeError::UndefinedWord(s) if s == "nonexistent")
457 );
458 }
459
460 #[test]
461 fn test_execute_string_simple() {
462 let mut interp = setup_interpreter();
463
464 execute_string("42 3.14", &mut interp).unwrap();
466
467 let result1 = interp.pop().unwrap();
469 let result2 = interp.pop().unwrap();
470
471 assert!(matches!(result1, Value::Number(n) if n == 3.14));
472 assert!(matches!(result2, Value::Int32(42))); }
474
475 #[test]
476 fn test_execute_string_with_builtin() {
477 let mut interp = setup_interpreter();
478
479 execute_string("5 3 +", &mut interp).unwrap();
481
482 let result = interp.pop().unwrap();
484 assert!(matches!(result, Value::Int32(8))); assert!(interp.pop().is_err());
488 }
489
490 #[test]
495 fn test_tail_recursive_factorial() {
496 let mut interp = setup_interpreter();
497
498 execute_string(
500 "'count-down [dup 1 <= [drop 999] [1 - count-down] if] def",
501 &mut interp,
502 )
503 .unwrap();
504
505 execute_string("5 count-down", &mut interp).unwrap();
507 let result = interp.pop().unwrap();
508 assert!(matches!(result, Value::Int32(999))); }
510
511 #[test]
512 fn test_deep_tail_recursion() {
513 let mut interp = setup_interpreter();
514
515 execute_string(
517 "'countdown [dup 0 <= [drop 42] [1 - countdown] if] def",
518 &mut interp,
519 )
520 .unwrap();
521
522 execute_string("1000 countdown", &mut interp).unwrap();
524 let result = interp.pop().unwrap();
525 assert!(matches!(result, Value::Int32(42))); }
527
528 #[test]
529 fn test_mutually_tail_recursive_functions() {
530 let mut interp = setup_interpreter();
531
532 execute_string("'even [dup 0 = [drop true] [1 - odd] if] def", &mut interp).unwrap();
534 execute_string("'odd [dup 0 = [drop false] [1 - even] if] def", &mut interp).unwrap();
535
536 execute_string("10 even", &mut interp).unwrap();
538 let result = interp.pop().unwrap();
539 assert!(matches!(result, Value::Boolean(true)));
540
541 execute_string("11 odd", &mut interp).unwrap();
542 let result = interp.pop().unwrap();
543 assert!(matches!(result, Value::Boolean(true)));
544 }
545
546 #[test]
547 fn test_tail_call_in_if_branches() {
548 let mut interp = setup_interpreter();
549
550 execute_string(
552 "'branch-test [dup 10 > [drop 99] [1 + branch-test] if] def",
553 &mut interp,
554 )
555 .unwrap();
556
557 execute_string("5 branch-test", &mut interp).unwrap();
558 let result = interp.pop().unwrap();
559 assert!(matches!(result, Value::Int32(99))); }
561
562 #[test]
563 fn test_execute_string_with_list() {
564 let mut interp = setup_interpreter();
565
566 execute_string("[1 2 +] 42", &mut interp).unwrap();
568
569 let number = interp.pop().unwrap();
571 let list = interp.pop().unwrap();
572
573 assert!(matches!(number, Value::Int32(42))); assert!(matches!(list, Value::Pair(_, _)));
575 }
576
577 #[test]
578 fn test_execute_quoted_atoms() {
579 let mut interp = setup_interpreter();
580
581 let hello_atom = interp.intern_atom("hello");
588 let quote_atom = interp.intern_atom("quote");
589
590 let quoted_hello = Value::Pair(
591 Rc::new(Value::Atom(quote_atom)),
592 Rc::new(Value::Pair(
593 Rc::new(Value::Atom(hello_atom)),
594 Rc::new(Value::Nil),
595 )),
596 );
597
598 execute("ed_hello, &mut interp).unwrap();
600
601 let result = interp.pop().unwrap();
602 assert!(matches!(result, Value::Pair(_, _)));
603 }
604
605 #[test]
606 fn test_execute_string_parse_errors() {
607 let mut interp = setup_interpreter();
608
609 let result = execute_string("[1 2", &mut interp); assert!(result.is_err());
612
613 let result = execute_string("'[1 2]", &mut interp); assert!(result.is_err());
615 }
616}