84 lines
2.3 KiB
Rust
84 lines
2.3 KiB
Rust
use fix_common::Symbol;
|
|
use fix_error::Error;
|
|
use gc_arena::Gc;
|
|
|
|
use crate::value::*;
|
|
use crate::{BytecodeReader, CallFrame, Step, VmRuntimeCtx, WithEnv};
|
|
|
|
impl<'gc> crate::Vm<'gc> {
|
|
#[inline(always)]
|
|
pub(crate) fn op_push_with(
|
|
&mut self,
|
|
ctx: &mut impl VmRuntimeCtx,
|
|
reader: &mut BytecodeReader<'_>,
|
|
mc: &gc_arena::Mutation<'gc>,
|
|
) -> Step {
|
|
let env = reader.read_operand_data(ctx).resolve(mc, self);
|
|
let scope = Gc::new(
|
|
mc,
|
|
WithEnv {
|
|
env,
|
|
prev: self.with_env,
|
|
},
|
|
);
|
|
self.with_env = Some(scope);
|
|
Step::Continue(())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn op_pop_with(&mut self) -> Step {
|
|
let Some(scope) = self.with_env else {
|
|
unreachable!("no with_scope to pop");
|
|
};
|
|
self.with_env = scope.prev;
|
|
Step::Continue(())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn op_prepare_with(&mut self) -> Step {
|
|
self.call_stack.push(CallFrame {
|
|
pc: usize::MAX,
|
|
stack_depth: 0,
|
|
thunk: None,
|
|
env: self.env,
|
|
with_env: self.with_env,
|
|
});
|
|
Step::Continue(())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn op_lookup_with(
|
|
&mut self,
|
|
ctx: &mut impl VmRuntimeCtx,
|
|
reader: &mut BytecodeReader<'_>,
|
|
mc: &gc_arena::Mutation<'gc>,
|
|
) -> Step {
|
|
let name = reader.read_string_id();
|
|
|
|
let Some(&WithEnv { env, prev }) = self.with_env.as_deref() else {
|
|
let Some(CallFrame { with_env, .. }) = self.call_stack.pop() else {
|
|
unreachable!()
|
|
};
|
|
self.with_env = with_env;
|
|
return self.finish_err(Error::eval_error(format!(
|
|
"undefined variable '{}'",
|
|
Symbol::from(ctx.resolve_string(name))
|
|
)));
|
|
};
|
|
self.push(env);
|
|
let env = self.try_force::<Gc<AttrSet>>(reader, mc)?;
|
|
let Some(val) = env.lookup(name) else {
|
|
reader.set_pc(reader.inst_start_pc());
|
|
self.with_env = prev;
|
|
return Step::Continue(());
|
|
};
|
|
|
|
self.push(val);
|
|
let Some(CallFrame { with_env, .. }) = self.call_stack.pop() else {
|
|
unreachable!()
|
|
};
|
|
self.with_env = with_env;
|
|
Step::Continue(())
|
|
}
|
|
}
|