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::>(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(()) } }