Implement `pushscope`, `popscope`, and `pushwith`.

This commit is contained in:
David Wendt 2020-02-11 14:46:47 -05:00
parent 5e6fc79f42
commit 78a1c9a7e3
3 changed files with 49 additions and 0 deletions

View File

@ -4,6 +4,7 @@ use crate::avm2::activation::Activation;
use crate::avm2::names::{Multiname, Namespace, QName}; use crate::avm2::names::{Multiname, Namespace, QName};
use crate::avm2::object::{Object, TObject}; use crate::avm2::object::{Object, TObject};
use crate::avm2::return_value::ReturnValue; use crate::avm2::return_value::ReturnValue;
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::context::UpdateContext; use crate::context::UpdateContext;
use crate::tag_utils::SwfSlice; use crate::tag_utils::SwfSlice;
@ -339,6 +340,9 @@ impl<'gc> Avm2<'gc> {
Op::ReturnVoid => self.op_return_void(context), Op::ReturnVoid => self.op_return_void(context),
Op::GetProperty { index } => self.op_get_property(context, index), Op::GetProperty { index } => self.op_get_property(context, index),
Op::SetProperty { index } => self.op_set_property(context, index), Op::SetProperty { index } => self.op_set_property(context, index),
Op::PushScope => self.op_push_scope(context),
Op::PushWith => self.op_push_with(context),
Op::PopScope => self.op_pop_scope(context),
Op::FindProperty { index } => self.op_find_property(context, index), Op::FindProperty { index } => self.op_find_property(context, index),
Op::FindPropStrict { index } => self.op_find_prop_strict(context, index), Op::FindPropStrict { index } => self.op_find_prop_strict(context, index),
Op::GetLex { index } => self.op_get_lex(context, index), Op::GetLex { index } => self.op_get_lex(context, index),
@ -499,6 +503,41 @@ impl<'gc> Avm2<'gc> {
} }
} }
fn op_push_scope(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> {
let object = self.pop().as_object()?;
let activation = self.current_stack_frame().unwrap();
let mut write = activation.write(context.gc_context);
let scope_stack = write.scope();
let new_scope = Scope::push_scope(scope_stack, object, context.gc_context);
write.set_scope(Some(new_scope));
Ok(())
}
fn op_push_with(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> {
let object = self.pop().as_object()?;
let activation = self.current_stack_frame().unwrap();
let mut write = activation.write(context.gc_context);
let scope_stack = write.scope();
let new_scope = Scope::push_with(scope_stack, object, context.gc_context);
write.set_scope(Some(new_scope));
Ok(())
}
fn op_pop_scope(&mut self, context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> {
let activation = self.current_stack_frame().unwrap();
let mut write = activation.write(context.gc_context);
let scope_stack = write.scope();
let new_scope = scope_stack.and_then(|s| s.read().pop_scope());
write.set_scope(new_scope);
Ok(())
}
fn op_find_property( fn op_find_property(
&mut self, &mut self,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,

View File

@ -158,10 +158,16 @@ impl<'gc> Activation<'gc> {
self.local_registers.read().get(id).cloned() self.local_registers.read().get(id).cloned()
} }
/// Get the current scope stack.
pub fn scope(&self) -> Option<GcCell<'gc, Scope<'gc>>> { pub fn scope(&self) -> Option<GcCell<'gc, Scope<'gc>>> {
self.scope self.scope
} }
/// Set a new scope stack.
pub fn set_scope(&mut self, new_scope: Option<GcCell<'gc, Scope<'gc>>>) {
self.scope = new_scope;
}
/// Set a local register. /// Set a local register.
/// ///
/// Returns `true` if the set was successful; `false` otherwise /// Returns `true` if the set was successful; `false` otherwise

View File

@ -69,6 +69,10 @@ impl<'gc> Scope<'gc> {
) )
} }
pub fn pop_scope(&self) -> Option<GcCell<'gc, Scope<'gc>>> {
self.parent
}
/// Construct a closure scope to be used as the scope stack when invoking a /// Construct a closure scope to be used as the scope stack when invoking a
/// function. /// function.
/// ///