Add 'again' keyword for recursive calls

The `again` keyword is introduced to facilitate explicit recursive
function calls.
It is restricted to tail-call positions to prevent dead code and ensure
TCO
optimization. Type checking is enhanced to validate argument types
against
function parameters.
This commit is contained in:
Michael Schimmel
2026-02-23 20:33:50 +01:00
parent be7ce31408
commit 4905b08548
13 changed files with 147 additions and 0 deletions
+31
View File
@@ -433,6 +433,37 @@ impl VM {
}
}
}
BoundKind::Again { args } => {
let arg_vals = match &args.kind {
BoundKind::Tuple { elements } => {
let mut vals = Vec::with_capacity(elements.len());
let mut is_complex = false;
for e in elements {
if matches!(e.kind, BoundKind::Tuple { .. }) {
is_complex = true;
break;
}
vals.push(self.eval_internal(obs, e)?);
}
if is_complex {
self.prepare_args_internal(obs, args)?
} else {
vals
}
}
_ => self.prepare_args_internal(obs, args)?,
};
let frame = self.frames.last().ok_or("No call frame for 'again'")?;
if let Some(closure) = &frame.closure {
Ok(Value::TailCallRequest(Box::new((
Rc::new(closure.as_ref().clone()) as Rc<dyn Object>,
arg_vals,
))))
} else {
Err("'again' called outside of a closure".to_string())
}
}
BoundKind::Tuple { elements } => {
let mut vals = Vec::with_capacity(elements.len());
for e in elements {