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:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user