Add Vm::exit_module
This does all of the routines necessary for exiting a module's execution. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -47,8 +47,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
|
||||
// run
|
||||
let module = upcast_obj(module);
|
||||
let mut vm = vm::Vm::new(&constants);
|
||||
vm.enter_module(upcast_obj(module));
|
||||
// VM needs the module to be on top of the stack when it executes
|
||||
vm.push(module.clone());
|
||||
vm.enter_module(module);
|
||||
vm.run();
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -81,43 +81,3 @@ impl Object for Module {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Module method implementations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
impl Module {
|
||||
pub(crate) fn execute(vm: &mut Vm, state: FunctionState) -> FunctionResult {
|
||||
match state {
|
||||
FunctionState::Begin => {
|
||||
let this = vm.frame_stack()[0].clone();
|
||||
let value = with_obj_downcast(this.clone(), |module: &Module| {
|
||||
module.evaluated_value.clone()
|
||||
});
|
||||
|
||||
// don't evaluate this twice
|
||||
if let Some(value) = value {
|
||||
return FunctionResult::ReturnPush(value);
|
||||
}
|
||||
|
||||
vm.enter_module(this.clone());
|
||||
FunctionResult::Yield(0)
|
||||
}
|
||||
FunctionState::Resume(0) => {
|
||||
let this = vm.frame_stack()[0].clone();
|
||||
let obj = with_obj_downcast(this.clone(), |module: &Module| {
|
||||
assert_eq!(module.globals().len(), vm.globals().len());
|
||||
let obj = Obj::create();
|
||||
module
|
||||
.globals()
|
||||
.iter()
|
||||
.zip(vm.globals())
|
||||
.for_each(|(name, value)| {
|
||||
obj.borrow_mut().set_attr(name, value.clone());
|
||||
});
|
||||
obj
|
||||
});
|
||||
FunctionResult::ReturnPush(obj)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
66
src/vm.rs
66
src/vm.rs
@@ -198,7 +198,17 @@ impl<'c> Vm<'c> {
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn enter_module(&mut self, module_ptr: ObjP) {
|
||||
/// Performs module entrance routines.
|
||||
///
|
||||
/// This **will not** check if the module has already been evaluated - this is up to the caller
|
||||
/// to do so.
|
||||
///
|
||||
/// This function will set the VM up for execution of a new module by:
|
||||
///
|
||||
/// 1. Create a new globals stack for the new module to use, and populate it with all of the
|
||||
/// globals that are used in the module.
|
||||
/// 2. Create and push a new module stack frame.
|
||||
pub(crate) fn enter_module(&mut self, module_ptr: ObjP) {
|
||||
with_obj_downcast(module_ptr.clone(), |module: &Module| {
|
||||
let mut globals: Vec<_> = module.globals().iter().map(|_| Nil::create()).collect();
|
||||
|
||||
@@ -227,6 +237,36 @@ impl<'c> Vm<'c> {
|
||||
});
|
||||
}
|
||||
|
||||
/// Performs module exit routines.
|
||||
///
|
||||
/// This expects that the module object that was executed is still on top of the stack. This
|
||||
/// will be popped, and the object represented by this module will be pushed to the stack.
|
||||
fn exit_module(&mut self) {
|
||||
let globals = self.globals.pop().expect("no globals");
|
||||
let old_frame = self.pop_frame();
|
||||
self.stack
|
||||
.resize_with(old_frame.stack_base, || unreachable!());
|
||||
|
||||
let module = self.pop();
|
||||
|
||||
// create the object and assign it as the module's evaluated value
|
||||
let obj = with_obj_downcast_mut(module, |module: &mut Module| {
|
||||
assert_eq!(module.globals().len(), globals.len());
|
||||
let obj = Obj::create();
|
||||
module
|
||||
.globals()
|
||||
.iter()
|
||||
.zip(globals)
|
||||
.for_each(|(name, value)| {
|
||||
obj.borrow_mut().set_attr(name, value.clone());
|
||||
});
|
||||
module.set_evaluated_value(Some(obj.clone()));
|
||||
obj
|
||||
});
|
||||
|
||||
self.push(obj);
|
||||
}
|
||||
|
||||
/// Get the current instruction and advance the IP.
|
||||
///
|
||||
/// This may actually end up calling a function on top of the stack, if it's a builtin function.
|
||||
@@ -447,34 +487,12 @@ impl<'c> Vm<'c> {
|
||||
}
|
||||
}
|
||||
Op::ExitModule => {
|
||||
let globals = self.globals.pop().unwrap();
|
||||
|
||||
let old_frame = self.pop_frame();
|
||||
self.stack
|
||||
.resize_with(old_frame.stack_base, || unreachable!());
|
||||
self.exit_module();
|
||||
|
||||
// halt execution if there aren't any globals left
|
||||
if self.globals.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
let module = self.pop();
|
||||
// create the object and assign it as the module's evaluated value
|
||||
let obj = with_obj_downcast_mut(module, |module: &mut Module| {
|
||||
assert_eq!(module.globals().len(), globals.len());
|
||||
let obj = Obj::create();
|
||||
module
|
||||
.globals()
|
||||
.iter()
|
||||
.zip(globals)
|
||||
.for_each(|(name, value)| {
|
||||
obj.borrow_mut().set_attr(name, value.clone());
|
||||
});
|
||||
module.set_evaluated_value(Some(obj.clone()));
|
||||
obj
|
||||
});
|
||||
|
||||
self.push(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user