Add Program node kind

The `Program` node kind is introduced to represent top-level code
blocks, distinguishing them from `Block` nodes which introduce new
scopes. This commit updates various compiler passes to handle the
`Program` node, ensuring correct AST traversal and processing.

The `Program` node is similar to `Block`, but its definitions propagate
to the enclosing scope, unlike `Block` which creates a new, isolated
scope. This distinction is important for how variables and functions are
resolved within the compiled code.
This commit is contained in:
2026-03-31 13:53:51 +02:00
parent 35f5ea0db3
commit 02ea2f0d80
15 changed files with 337 additions and 209 deletions
+15 -10
View File
@@ -266,22 +266,27 @@ impl VM {
self.resolve_tail_calls(observer, result)
}
pub fn run_with_observer<O: VMObserver>(
&mut self,
observer: &mut O,
root: &ExecNode,
) -> Result<Value, String> {
self.stack.clear();
pub fn eval_in_frame<O: VMObserver>(&mut self, observer: &mut O, root: &ExecNode, stack: Vec<Value>) -> Result<Value, String> {
self.stack = stack;
self.frames.clear();
self.stack.resize(root.ty.stack_size as usize, Value::Void);
self.frames.push(CallFrame {
stack_base: 0,
closure: None,
});
let result = self.eval_internal(observer, root);
self.frames.pop();
result
}
pub fn run_with_observer<O: VMObserver>(
&mut self,
observer: &mut O,
root: &ExecNode,
) -> Result<Value, String> {
let mut stack = Vec::new();
stack.resize(root.ty.stack_size as usize, Value::Void);
let result = self.eval_in_frame(observer, root, stack);
self.resolve_tail_calls(observer, result)
}
@@ -438,7 +443,7 @@ impl VM {
Ok(Value::Void)
}
}
NodeKind::Block { exprs } => {
NodeKind::Block { exprs } | NodeKind::Program { exprs } => {
let mut last = Value::Void;
for e in exprs {
last = self.eval_internal(obs, e)?;