avm2: AVM2 built-in class suport (merge #802)
Initial support for defining built-ins in AVM2
This commit is contained in:
commit
f782ea8020
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::globals::SystemPrototypes;
|
use crate::avm2::globals::SystemPrototypes;
|
||||||
use crate::avm2::object::{Object, TObject};
|
use crate::avm2::object::{Object, ScriptObject, TObject};
|
||||||
use crate::avm2::scope::Scope;
|
use crate::avm2::scope::Scope;
|
||||||
use crate::avm2::script::Script;
|
use crate::avm2::script::Script;
|
||||||
use crate::avm2::script::TranslationUnit;
|
use crate::avm2::script::TranslationUnit;
|
||||||
|
@ -36,7 +36,7 @@ mod scope;
|
||||||
mod script;
|
mod script;
|
||||||
mod slot;
|
mod slot;
|
||||||
mod string;
|
mod string;
|
||||||
mod r#trait;
|
mod traits;
|
||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
/// Boxed error alias.
|
/// Boxed error alias.
|
||||||
|
@ -56,7 +56,7 @@ pub struct Avm2<'gc> {
|
||||||
globals: Object<'gc>,
|
globals: Object<'gc>,
|
||||||
|
|
||||||
/// System prototypes.
|
/// System prototypes.
|
||||||
system_prototypes: SystemPrototypes<'gc>,
|
system_prototypes: Option<SystemPrototypes<'gc>>,
|
||||||
|
|
||||||
#[cfg(feature = "avm_debug")]
|
#[cfg(feature = "avm_debug")]
|
||||||
pub debug_output: bool,
|
pub debug_output: bool,
|
||||||
|
@ -65,21 +65,28 @@ pub struct Avm2<'gc> {
|
||||||
impl<'gc> Avm2<'gc> {
|
impl<'gc> Avm2<'gc> {
|
||||||
/// Construct a new AVM interpreter.
|
/// Construct a new AVM interpreter.
|
||||||
pub fn new(mc: MutationContext<'gc, '_>) -> Self {
|
pub fn new(mc: MutationContext<'gc, '_>) -> Self {
|
||||||
let (globals, system_prototypes) = globals::construct_global_scope(mc);
|
let globals = ScriptObject::bare_object(mc);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
globals,
|
globals,
|
||||||
system_prototypes,
|
system_prototypes: None,
|
||||||
|
|
||||||
#[cfg(feature = "avm_debug")]
|
#[cfg(feature = "avm_debug")]
|
||||||
debug_output: false,
|
debug_output: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_player_globals(context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> {
|
||||||
|
let mut activation = Activation::from_nothing(context.reborrow());
|
||||||
|
globals::load_player_globals(&mut activation)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the current set of system prototypes.
|
/// Return the current set of system prototypes.
|
||||||
|
///
|
||||||
|
/// This function panics if the interpreter has not yet been initialized.
|
||||||
pub fn prototypes(&self) -> &SystemPrototypes<'gc> {
|
pub fn prototypes(&self) -> &SystemPrototypes<'gc> {
|
||||||
&self.system_prototypes
|
self.system_prototypes.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run a script's initializer method.
|
/// Run a script's initializer method.
|
||||||
|
|
|
@ -2,13 +2,30 @@
|
||||||
|
|
||||||
use crate::avm2::method::Method;
|
use crate::avm2::method::Method;
|
||||||
use crate::avm2::names::{Multiname, Namespace, QName};
|
use crate::avm2::names::{Multiname, Namespace, QName};
|
||||||
use crate::avm2::r#trait::{Trait, TraitKind};
|
|
||||||
use crate::avm2::script::TranslationUnit;
|
use crate::avm2::script::TranslationUnit;
|
||||||
use crate::avm2::string::AvmString;
|
use crate::avm2::string::AvmString;
|
||||||
|
use crate::avm2::traits::{Trait, TraitKind};
|
||||||
use crate::avm2::{Avm2, Error};
|
use crate::avm2::{Avm2, Error};
|
||||||
|
use crate::collect::CollectWrapper;
|
||||||
|
use enumset::{EnumSet, EnumSetType};
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
use swf::avm2::types::{Class as AbcClass, Instance as AbcInstance};
|
use swf::avm2::types::{Class as AbcClass, Instance as AbcInstance};
|
||||||
|
|
||||||
|
/// All possible attributes for a given class.
|
||||||
|
#[derive(EnumSetType, Debug)]
|
||||||
|
pub enum ClassAttributes {
|
||||||
|
/// Class is sealed, attempts to set or init dynamic properties on an
|
||||||
|
/// object will generate a runtime error.
|
||||||
|
Sealed,
|
||||||
|
|
||||||
|
/// Class is final, attempts to construct child classes from it will
|
||||||
|
/// generate a verification error.
|
||||||
|
Final,
|
||||||
|
|
||||||
|
/// Class is an interface.
|
||||||
|
Interface,
|
||||||
|
}
|
||||||
|
|
||||||
/// A loaded ABC Class which can be used to construct objects with.
|
/// A loaded ABC Class which can be used to construct objects with.
|
||||||
#[derive(Clone, Debug, Collect)]
|
#[derive(Clone, Debug, Collect)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
|
@ -19,14 +36,8 @@ pub struct Class<'gc> {
|
||||||
/// The name of this class's superclass.
|
/// The name of this class's superclass.
|
||||||
super_class: Option<Multiname<'gc>>,
|
super_class: Option<Multiname<'gc>>,
|
||||||
|
|
||||||
/// If this class is sealed (dynamic property writes should fail)
|
/// Attributes of the given class.
|
||||||
is_sealed: bool,
|
attributes: CollectWrapper<EnumSet<ClassAttributes>>,
|
||||||
|
|
||||||
/// If this class is final (subclassing should fail)
|
|
||||||
is_final: bool,
|
|
||||||
|
|
||||||
/// If this class is an interface
|
|
||||||
is_interface: bool,
|
|
||||||
|
|
||||||
/// The namespace that protected traits of this class are stored into.
|
/// The namespace that protected traits of this class are stored into.
|
||||||
protected_namespace: Option<Namespace<'gc>>,
|
protected_namespace: Option<Namespace<'gc>>,
|
||||||
|
@ -97,6 +108,48 @@ fn do_trait_lookup<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> Class<'gc> {
|
impl<'gc> Class<'gc> {
|
||||||
|
/// Create a new class.
|
||||||
|
///
|
||||||
|
/// This function is primarily intended for use by native code to define
|
||||||
|
/// builtin classes. The absolute minimum necessary to define a class is
|
||||||
|
/// required here; further methods allow further changes to the class.
|
||||||
|
///
|
||||||
|
/// Classes created in this way cannot have traits loaded from an ABC file
|
||||||
|
/// using `load_traits`.
|
||||||
|
pub fn new(
|
||||||
|
name: QName<'gc>,
|
||||||
|
super_class: Option<Multiname<'gc>>,
|
||||||
|
instance_init: Method<'gc>,
|
||||||
|
class_init: Method<'gc>,
|
||||||
|
mc: MutationContext<'gc, '_>,
|
||||||
|
) -> GcCell<'gc, Self> {
|
||||||
|
GcCell::allocate(
|
||||||
|
mc,
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
super_class,
|
||||||
|
attributes: CollectWrapper(EnumSet::empty()),
|
||||||
|
protected_namespace: None,
|
||||||
|
interfaces: Vec::new(),
|
||||||
|
instance_init,
|
||||||
|
instance_traits: Vec::new(),
|
||||||
|
class_init,
|
||||||
|
class_traits: Vec::new(),
|
||||||
|
traits_loaded: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the attributes of the class (sealed/final/interface status).
|
||||||
|
pub fn set_attributes(&mut self, attributes: EnumSet<ClassAttributes>) {
|
||||||
|
self.attributes = CollectWrapper(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a protected namespace to this class.
|
||||||
|
pub fn set_protected_namespace(&mut self, ns: Namespace<'gc>) {
|
||||||
|
self.protected_namespace = Some(ns)
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a class from a `TranslationUnit` and it's class index.
|
/// Construct a class from a `TranslationUnit` and it's class index.
|
||||||
///
|
///
|
||||||
/// The returned class will be allocated, but no traits will be loaded. The
|
/// The returned class will be allocated, but no traits will be loaded. The
|
||||||
|
@ -149,14 +202,25 @@ impl<'gc> Class<'gc> {
|
||||||
let instance_init = unit.load_method(abc_instance.init_method.0, mc)?;
|
let instance_init = unit.load_method(abc_instance.init_method.0, mc)?;
|
||||||
let class_init = unit.load_method(abc_class.init_method.0, mc)?;
|
let class_init = unit.load_method(abc_class.init_method.0, mc)?;
|
||||||
|
|
||||||
|
let mut attributes = EnumSet::new();
|
||||||
|
if abc_instance.is_sealed {
|
||||||
|
attributes |= ClassAttributes::Sealed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if abc_instance.is_final {
|
||||||
|
attributes |= ClassAttributes::Final;
|
||||||
|
}
|
||||||
|
|
||||||
|
if abc_instance.is_interface {
|
||||||
|
attributes |= ClassAttributes::Interface;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(GcCell::allocate(
|
Ok(GcCell::allocate(
|
||||||
mc,
|
mc,
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
super_class,
|
super_class,
|
||||||
is_sealed: abc_instance.is_sealed,
|
attributes: CollectWrapper(attributes),
|
||||||
is_final: abc_instance.is_final,
|
|
||||||
is_interface: abc_instance.is_interface,
|
|
||||||
protected_namespace,
|
protected_namespace,
|
||||||
interfaces,
|
interfaces,
|
||||||
instance_init,
|
instance_init,
|
||||||
|
@ -221,6 +285,14 @@ impl<'gc> Class<'gc> {
|
||||||
&self.super_class
|
&self.super_class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Define a trait on the class.
|
||||||
|
///
|
||||||
|
/// Class traits will be accessible as properties on the class constructor
|
||||||
|
/// function.
|
||||||
|
pub fn define_class_trait(&mut self, my_trait: Trait<'gc>) {
|
||||||
|
self.class_traits.push(my_trait);
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a name, append class traits matching the name to a list of known
|
/// Given a name, append class traits matching the name to a list of known
|
||||||
/// traits.
|
/// traits.
|
||||||
///
|
///
|
||||||
|
@ -265,6 +337,15 @@ impl<'gc> Class<'gc> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Define a trait on instances of the class.
|
||||||
|
///
|
||||||
|
/// Instance traits will be accessible as properties on instances of the
|
||||||
|
/// class. They will not be accessible on the class prototype, and any
|
||||||
|
/// properties defined on the prototype will be shadowed by these traits.
|
||||||
|
pub fn define_instance_trait(&mut self, my_trait: Trait<'gc>) {
|
||||||
|
self.class_traits.push(my_trait);
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a name, append instance traits matching the name to a list of
|
/// Given a name, append instance traits matching the name to a list of
|
||||||
/// known traits.
|
/// known traits.
|
||||||
///
|
///
|
||||||
|
@ -322,4 +403,8 @@ impl<'gc> Class<'gc> {
|
||||||
pub fn interfaces(&self) -> &[Multiname<'gc>] {
|
pub fn interfaces(&self) -> &[Multiname<'gc>] {
|
||||||
&self.interfaces
|
&self.interfaces
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn implements(&mut self, iface: Multiname<'gc>) {
|
||||||
|
self.interfaces.push(iface)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
//! Global scope built-ins
|
//! Global scope built-ins
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
|
use crate::avm2::class::Class;
|
||||||
use crate::avm2::method::NativeMethod;
|
use crate::avm2::method::NativeMethod;
|
||||||
use crate::avm2::names::{Namespace, QName};
|
use crate::avm2::names::{Namespace, QName};
|
||||||
use crate::avm2::object::{FunctionObject, ScriptObject};
|
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
|
||||||
use crate::avm2::object::{Object, TObject};
|
use crate::avm2::scope::Scope;
|
||||||
use crate::avm2::string::AvmString;
|
use crate::avm2::string::AvmString;
|
||||||
|
use crate::avm2::traits::Trait;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::{Collect, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
use std::f64::NAN;
|
use std::f64::NAN;
|
||||||
|
|
||||||
mod boolean;
|
mod boolean;
|
||||||
|
@ -49,6 +51,34 @@ pub struct SystemPrototypes<'gc> {
|
||||||
pub namespace: Object<'gc>,
|
pub namespace: Object<'gc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'gc> SystemPrototypes<'gc> {
|
||||||
|
/// Construct a minimal set of system prototypes necessary for
|
||||||
|
/// bootstrapping player globals.
|
||||||
|
///
|
||||||
|
/// All other system prototypes aside from the three given here will be set
|
||||||
|
/// to the empty object also handed to this function. It is the caller's
|
||||||
|
/// responsibility to instantiate each class and replace the empty object
|
||||||
|
/// with that.
|
||||||
|
fn new(
|
||||||
|
object: Object<'gc>,
|
||||||
|
function: Object<'gc>,
|
||||||
|
class: Object<'gc>,
|
||||||
|
empty: Object<'gc>,
|
||||||
|
) -> Self {
|
||||||
|
SystemPrototypes {
|
||||||
|
object,
|
||||||
|
function,
|
||||||
|
class,
|
||||||
|
string: empty,
|
||||||
|
boolean: empty,
|
||||||
|
number: empty,
|
||||||
|
int: empty,
|
||||||
|
uint: empty,
|
||||||
|
namespace: empty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a free-function builtin to the global scope.
|
/// Add a free-function builtin to the global scope.
|
||||||
fn function<'gc>(
|
fn function<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
mc: MutationContext<'gc, '_>,
|
||||||
|
@ -67,25 +97,47 @@ fn function<'gc>(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a class builtin to the global scope.
|
/// Add a class builtin with prototype methods to the global scope.
|
||||||
fn class<'gc>(
|
///
|
||||||
|
/// Since the function has to return a normal prototype object in this case, we
|
||||||
|
/// have to construct a constructor to go along with it, as if we had called
|
||||||
|
/// `install_foreign_trait` with such a class.
|
||||||
|
fn dynamic_class<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
mc: MutationContext<'gc, '_>,
|
||||||
mut global_scope: Object<'gc>,
|
mut global_scope: Object<'gc>,
|
||||||
package: impl Into<AvmString<'gc>>,
|
constr: Object<'gc>,
|
||||||
name: impl Into<AvmString<'gc>>,
|
|
||||||
constr: NativeMethod<'gc>,
|
|
||||||
proto: Object<'gc>,
|
|
||||||
fn_proto: Object<'gc>,
|
|
||||||
) {
|
) {
|
||||||
global_scope
|
let name = constr
|
||||||
.install_dynamic_property(
|
.as_class()
|
||||||
mc,
|
.expect("constrs have classes in them")
|
||||||
QName::new(Namespace::package(package), name),
|
.read()
|
||||||
FunctionObject::from_builtin_constr(mc, constr, proto, fn_proto)
|
.name()
|
||||||
.unwrap()
|
.clone();
|
||||||
.into(),
|
|
||||||
)
|
global_scope.install_const(mc, name, 0, constr.into());
|
||||||
.unwrap();
|
}
|
||||||
|
|
||||||
|
/// Add a class builtin to the global scope.
|
||||||
|
///
|
||||||
|
/// This function returns a prototype which may be stored in `SystemPrototypes`.
|
||||||
|
fn class<'gc>(
|
||||||
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
mut global: Object<'gc>,
|
||||||
|
class_def: GcCell<'gc, Class<'gc>>,
|
||||||
|
) -> Result<Object<'gc>, Error> {
|
||||||
|
let class_trait = Trait::from_class(class_def);
|
||||||
|
let global_scope = Scope::push_scope(global.get_scope(), global, activation.context.gc_context);
|
||||||
|
let mut constr = global
|
||||||
|
.install_foreign_trait(activation, class_trait, Some(global_scope), global)?
|
||||||
|
.coerce_to_object(activation)?;
|
||||||
|
|
||||||
|
constr
|
||||||
|
.get_property(
|
||||||
|
constr,
|
||||||
|
&QName::new(Namespace::public_namespace(), "prototype"),
|
||||||
|
activation,
|
||||||
|
)?
|
||||||
|
.coerce_to_object(activation)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a builtin constant to the global scope.
|
/// Add a builtin constant to the global scope.
|
||||||
|
@ -99,181 +151,132 @@ fn constant<'gc>(
|
||||||
global_scope.install_const(mc, QName::new(Namespace::package(package), name), 0, value)
|
global_scope.install_const(mc, QName::new(Namespace::package(package), name), 0, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a new global scope.
|
/// Initialize all remaining builtin classes.
|
||||||
///
|
///
|
||||||
/// This function returns both the global scope object, as well as all builtin
|
/// This should be called only once, to construct the global scope of the
|
||||||
/// prototypes that other parts of the VM will need to use.
|
/// player. It will return a list of prototypes it has created, which should be
|
||||||
pub fn construct_global_scope<'gc>(
|
/// stored on the AVM.
|
||||||
mc: MutationContext<'gc, '_>,
|
pub fn load_player_globals<'gc>(activation: &mut Activation<'_, 'gc, '_>) -> Result<(), Error> {
|
||||||
) -> (Object<'gc>, SystemPrototypes<'gc>) {
|
let gs = activation.avm2().globals();
|
||||||
let gs = ScriptObject::bare_object(mc);
|
|
||||||
|
|
||||||
// public / root package
|
// public / root package
|
||||||
let object_proto = ScriptObject::bare_object(mc);
|
let object_proto = object::create_proto(activation);
|
||||||
let fn_proto = function::create_proto(mc, object_proto);
|
let (function_constr, fn_proto) = function::create_class(activation, object_proto);
|
||||||
let class_proto = class::create_proto(mc, object_proto, fn_proto);
|
let (class_constr, class_proto) = class::create_class(activation, object_proto, fn_proto);
|
||||||
let string_proto = string::create_proto(mc, object_proto, fn_proto);
|
|
||||||
let boolean_proto = boolean::create_proto(mc, object_proto, fn_proto);
|
|
||||||
let number_proto = number::create_proto(mc, object_proto, fn_proto);
|
|
||||||
let int_proto = int::create_proto(mc, object_proto, fn_proto);
|
|
||||||
let uint_proto = uint::create_proto(mc, object_proto, fn_proto);
|
|
||||||
let namespace_proto = namespace::create_proto(mc, object_proto, fn_proto);
|
|
||||||
|
|
||||||
object::fill_proto(mc, object_proto, fn_proto);
|
let object_constr = object::fill_proto(activation.context.gc_context, object_proto, fn_proto);
|
||||||
|
|
||||||
class(
|
dynamic_class(activation.context.gc_context, gs, object_constr);
|
||||||
mc,
|
dynamic_class(activation.context.gc_context, gs, function_constr);
|
||||||
gs,
|
dynamic_class(activation.context.gc_context, gs, class_constr);
|
||||||
"",
|
|
||||||
"Object",
|
// At this point, we need at least a partial set of system prototypes in
|
||||||
object::constructor,
|
// order to continue initializing the player. The rest of the prototypes
|
||||||
|
// are set to a bare object until we have a chance to initialize them.
|
||||||
|
activation.context.avm2.system_prototypes = Some(SystemPrototypes::new(
|
||||||
object_proto,
|
object_proto,
|
||||||
fn_proto,
|
fn_proto,
|
||||||
);
|
|
||||||
class(
|
|
||||||
mc,
|
|
||||||
gs,
|
|
||||||
"",
|
|
||||||
"Function",
|
|
||||||
function::constructor,
|
|
||||||
fn_proto,
|
|
||||||
fn_proto,
|
|
||||||
);
|
|
||||||
class(
|
|
||||||
mc,
|
|
||||||
gs,
|
|
||||||
"",
|
|
||||||
"Class",
|
|
||||||
class::constructor,
|
|
||||||
class_proto,
|
class_proto,
|
||||||
fn_proto,
|
ScriptObject::bare_object(activation.context.gc_context),
|
||||||
);
|
));
|
||||||
class(
|
|
||||||
mc,
|
// Even sillier: for the sake of clarity and the borrow checker we need to
|
||||||
|
// clone the prototypes list and modify it outside of the activation. This
|
||||||
|
// also has the side effect that none of these classes can get at each
|
||||||
|
// other from the activation they're handed.
|
||||||
|
let mut sp = activation.context.avm2.system_prototypes.clone().unwrap();
|
||||||
|
|
||||||
|
sp.string = class(
|
||||||
|
activation,
|
||||||
|
gs,
|
||||||
|
string::create_class(activation.context.gc_context),
|
||||||
|
)?;
|
||||||
|
sp.boolean = class(
|
||||||
|
activation,
|
||||||
|
gs,
|
||||||
|
boolean::create_class(activation.context.gc_context),
|
||||||
|
)?;
|
||||||
|
sp.number = class(
|
||||||
|
activation,
|
||||||
|
gs,
|
||||||
|
number::create_class(activation.context.gc_context),
|
||||||
|
)?;
|
||||||
|
sp.int = class(
|
||||||
|
activation,
|
||||||
|
gs,
|
||||||
|
int::create_class(activation.context.gc_context),
|
||||||
|
)?;
|
||||||
|
sp.uint = class(
|
||||||
|
activation,
|
||||||
|
gs,
|
||||||
|
uint::create_class(activation.context.gc_context),
|
||||||
|
)?;
|
||||||
|
sp.namespace = class(
|
||||||
|
activation,
|
||||||
|
gs,
|
||||||
|
namespace::create_class(activation.context.gc_context),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
activation.context.avm2.system_prototypes = Some(sp);
|
||||||
|
|
||||||
|
function(
|
||||||
|
activation.context.gc_context,
|
||||||
gs,
|
gs,
|
||||||
"",
|
"",
|
||||||
"String",
|
"trace",
|
||||||
string::constructor,
|
trace,
|
||||||
string_proto,
|
|
||||||
fn_proto,
|
fn_proto,
|
||||||
);
|
);
|
||||||
class(
|
constant(
|
||||||
mc,
|
activation.context.gc_context,
|
||||||
gs,
|
gs,
|
||||||
"",
|
"",
|
||||||
"Boolean",
|
"undefined",
|
||||||
boolean::constructor,
|
Value::Undefined,
|
||||||
boolean_proto,
|
|
||||||
fn_proto,
|
|
||||||
);
|
);
|
||||||
class(
|
constant(activation.context.gc_context, gs, "", "null", Value::Null);
|
||||||
mc,
|
constant(activation.context.gc_context, gs, "", "NaN", NAN.into());
|
||||||
|
constant(
|
||||||
|
activation.context.gc_context,
|
||||||
gs,
|
gs,
|
||||||
"",
|
"",
|
||||||
"Number",
|
"Infinity",
|
||||||
number::constructor,
|
f64::INFINITY.into(),
|
||||||
number_proto,
|
|
||||||
fn_proto,
|
|
||||||
);
|
);
|
||||||
class(mc, gs, "", "int", int::constructor, int_proto, fn_proto);
|
|
||||||
class(mc, gs, "", "uint", uint::constructor, uint_proto, fn_proto);
|
|
||||||
class(
|
|
||||||
mc,
|
|
||||||
gs,
|
|
||||||
"",
|
|
||||||
"Namespace",
|
|
||||||
namespace::constructor,
|
|
||||||
namespace_proto,
|
|
||||||
fn_proto,
|
|
||||||
);
|
|
||||||
function(mc, gs, "", "trace", trace, fn_proto);
|
|
||||||
constant(mc, gs, "", "undefined", Value::Undefined);
|
|
||||||
constant(mc, gs, "", "null", Value::Null);
|
|
||||||
constant(mc, gs, "", "NaN", NAN.into());
|
|
||||||
constant(mc, gs, "", "Infinity", f64::INFINITY.into());
|
|
||||||
|
|
||||||
// package `flash.events`
|
// package `flash.events`
|
||||||
let eventdispatcher_proto =
|
|
||||||
flash::events::eventdispatcher::create_proto(mc, object_proto, fn_proto);
|
|
||||||
|
|
||||||
class(
|
class(
|
||||||
mc,
|
activation,
|
||||||
gs,
|
gs,
|
||||||
"flash.events",
|
flash::events::eventdispatcher::create_class(activation.context.gc_context),
|
||||||
"EventDispatcher",
|
)?;
|
||||||
flash::events::eventdispatcher::constructor,
|
|
||||||
eventdispatcher_proto,
|
|
||||||
fn_proto,
|
|
||||||
);
|
|
||||||
|
|
||||||
// package `flash.display`
|
// package `flash.display`
|
||||||
let displayobject_proto =
|
class(
|
||||||
flash::display::displayobject::create_proto(mc, eventdispatcher_proto, fn_proto);
|
activation,
|
||||||
let interactiveobject_proto =
|
gs,
|
||||||
flash::display::interactiveobject::create_proto(mc, displayobject_proto, fn_proto);
|
flash::display::displayobject::create_class(activation.context.gc_context),
|
||||||
let displayobjectcontainer_proto =
|
)?;
|
||||||
flash::display::displayobjectcontainer::create_proto(mc, interactiveobject_proto, fn_proto);
|
class(
|
||||||
let sprite_proto =
|
activation,
|
||||||
flash::display::sprite::create_proto(mc, displayobjectcontainer_proto, fn_proto);
|
gs,
|
||||||
let movieclip_proto = flash::display::movieclip::create_proto(mc, sprite_proto, fn_proto);
|
flash::display::interactiveobject::create_class(activation.context.gc_context),
|
||||||
|
)?;
|
||||||
|
class(
|
||||||
|
activation,
|
||||||
|
gs,
|
||||||
|
flash::display::displayobjectcontainer::create_class(activation.context.gc_context),
|
||||||
|
)?;
|
||||||
|
class(
|
||||||
|
activation,
|
||||||
|
gs,
|
||||||
|
flash::display::sprite::create_class(activation.context.gc_context),
|
||||||
|
)?;
|
||||||
|
class(
|
||||||
|
activation,
|
||||||
|
gs,
|
||||||
|
flash::display::movieclip::create_class(activation.context.gc_context),
|
||||||
|
)?;
|
||||||
|
|
||||||
class(
|
Ok(())
|
||||||
mc,
|
|
||||||
gs,
|
|
||||||
"flash.display",
|
|
||||||
"DisplayObject",
|
|
||||||
flash::display::displayobject::constructor,
|
|
||||||
displayobject_proto,
|
|
||||||
fn_proto,
|
|
||||||
);
|
|
||||||
class(
|
|
||||||
mc,
|
|
||||||
gs,
|
|
||||||
"flash.display",
|
|
||||||
"InteractiveObject",
|
|
||||||
flash::display::interactiveobject::constructor,
|
|
||||||
interactiveobject_proto,
|
|
||||||
fn_proto,
|
|
||||||
);
|
|
||||||
class(
|
|
||||||
mc,
|
|
||||||
gs,
|
|
||||||
"flash.display",
|
|
||||||
"DisplayObjectContainer",
|
|
||||||
flash::display::displayobjectcontainer::constructor,
|
|
||||||
sprite_proto,
|
|
||||||
fn_proto,
|
|
||||||
);
|
|
||||||
class(
|
|
||||||
mc,
|
|
||||||
gs,
|
|
||||||
"flash.display",
|
|
||||||
"Sprite",
|
|
||||||
flash::display::sprite::constructor,
|
|
||||||
sprite_proto,
|
|
||||||
fn_proto,
|
|
||||||
);
|
|
||||||
class(
|
|
||||||
mc,
|
|
||||||
gs,
|
|
||||||
"flash.display",
|
|
||||||
"MovieClip",
|
|
||||||
flash::display::movieclip::constructor,
|
|
||||||
movieclip_proto,
|
|
||||||
fn_proto,
|
|
||||||
);
|
|
||||||
|
|
||||||
let system_prototypes = SystemPrototypes {
|
|
||||||
object: object_proto,
|
|
||||||
function: fn_proto,
|
|
||||||
class: class_proto,
|
|
||||||
string: string_proto,
|
|
||||||
boolean: boolean_proto,
|
|
||||||
number: number_proto,
|
|
||||||
int: int_proto,
|
|
||||||
uint: uint_proto,
|
|
||||||
namespace: namespace_proto,
|
|
||||||
};
|
|
||||||
|
|
||||||
(gs, system_prototypes)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `Boolean` impl
|
//! `Boolean` impl
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `Boolean`
|
/// Implements `Boolean`'s instance initializer.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
||||||
Err("Boolean constructor is a stub.".into())
|
Err("Boolean constructor is a stub.".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `Boolean.prototype`.
|
/// Implements `Boolean`'s class initializer.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
ScriptObject::object(mc, super_proto)
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct `Boolean`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(Namespace::package(""), "Boolean"),
|
||||||
|
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
//! `Class` builtin/prototype
|
//! `Class` builtin/prototype
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
|
||||||
|
use crate::avm2::scope::Scope;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
|
||||||
|
|
||||||
/// Implements `Class`
|
/// Implements `Class`'s instance initializer.
|
||||||
///
|
///
|
||||||
/// Notably, you cannot construct new classes this way, so this returns an
|
/// Notably, you cannot construct new classes this way, so this returns an
|
||||||
/// error.
|
/// error.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -18,11 +21,45 @@ pub fn constructor<'gc>(
|
||||||
Err("Classes cannot be constructed.".into())
|
Err("Classes cannot be constructed.".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `Class.prototype`.
|
/// Implement's `Class`'s class initializer.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
ScriptObject::object(mc, super_proto)
|
Err("Classes cannot be constructed.".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct `Class` and `Class.prototype`, respectively.
|
||||||
|
pub fn create_class<'gc>(
|
||||||
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
super_proto: Object<'gc>,
|
||||||
|
fn_proto: Object<'gc>,
|
||||||
|
) -> (Object<'gc>, Object<'gc>) {
|
||||||
|
let class_class = Class::new(
|
||||||
|
QName::new(Namespace::public_namespace(), "Class"),
|
||||||
|
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
activation.context.gc_context,
|
||||||
|
);
|
||||||
|
|
||||||
|
let globals = activation.avm2().globals();
|
||||||
|
let scope = Scope::push_scope(globals.get_scope(), globals, activation.context.gc_context);
|
||||||
|
let proto = ScriptObject::prototype(
|
||||||
|
activation.context.gc_context,
|
||||||
|
super_proto,
|
||||||
|
class_class,
|
||||||
|
Some(scope),
|
||||||
|
);
|
||||||
|
|
||||||
|
let constr = FunctionObject::from_builtin_constr(
|
||||||
|
activation.context.gc_context,
|
||||||
|
instance_init,
|
||||||
|
proto,
|
||||||
|
fn_proto,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
(constr, proto)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `flash.display.DisplayObject` builtin/prototype
|
//! `flash.display.DisplayObject` builtin/prototype
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `flash.display.DisplayObject`'s constructor.
|
/// Implements `flash.display.DisplayObject`'s instance constructor.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,12 +18,22 @@ pub fn constructor<'gc>(
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `DisplayObject.prototype`.
|
/// Implements `flash.display.DisplayObject`'s class constructor.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
// TODO: Use `StageObject` here.
|
Ok(Value::Undefined)
|
||||||
ScriptObject::object(mc, super_proto)
|
}
|
||||||
|
|
||||||
|
/// Construct `DisplayObject`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(Namespace::package("flash.display"), "DisplayObject"),
|
||||||
|
Some(QName::new(Namespace::package("flash.events"), "EventDispatcher").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `flash.display.DisplayObjectContainer` builtin/prototype
|
//! `flash.display.DisplayObjectContainer` builtin/prototype
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `flash.display.DisplayObjectContainer`'s constructor.
|
/// Implements `flash.display.DisplayObjectContainer`'s instance constructor.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,12 +18,25 @@ pub fn constructor<'gc>(
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `DisplayObjectContainer.prototype`.
|
/// Implements `flash.display.DisplayObjectContainer`'s class constructor.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
// TODO: Use `StageObject` here.
|
Ok(Value::Undefined)
|
||||||
ScriptObject::object(mc, super_proto)
|
}
|
||||||
|
|
||||||
|
/// Construct `DisplayObjectContainer`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(
|
||||||
|
Namespace::package("flash.display"),
|
||||||
|
"DisplayObjectContainer",
|
||||||
|
),
|
||||||
|
Some(QName::new(Namespace::package("flash.display"), "InteractiveObject").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `flash.display.InteractiveObject` builtin/prototype
|
//! `flash.display.InteractiveObject` builtin/prototype
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `flash.display.InteractiveObject`'s constructor.
|
/// Implements `flash.display.InteractiveObject`'s instance constructor.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,12 +18,22 @@ pub fn constructor<'gc>(
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `InteractiveObject.prototype`.
|
/// Implements `flash.display.InteractiveObject`'s class constructor.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
// TODO: Use `StageObject` here.
|
Ok(Value::Undefined)
|
||||||
ScriptObject::object(mc, super_proto)
|
}
|
||||||
|
|
||||||
|
/// Construct `InteractiveObject`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(Namespace::package("flash.display"), "InteractiveObject"),
|
||||||
|
Some(QName::new(Namespace::package("flash.display"), "DisplayObject").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `flash.display.MovieClip` builtin/prototype
|
//! `flash.display.MovieClip` builtin/prototype
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `flash.display.MovieClip`'s constructor.
|
/// Implements `flash.display.MovieClip`'s instance constructor.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,12 +18,22 @@ pub fn constructor<'gc>(
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `MovieClip.prototype`.
|
/// Implements `flash.display.MovieClip`'s class constructor.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
// TODO: Use `StageObject` here.
|
Ok(Value::Undefined)
|
||||||
ScriptObject::object(mc, super_proto)
|
}
|
||||||
|
|
||||||
|
/// Construct `MovieClip`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(Namespace::package("flash.display"), "MovieClip"),
|
||||||
|
Some(QName::new(Namespace::package("flash.display"), "Sprite").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `flash.display.Sprite` builtin/prototype
|
//! `flash.display.Sprite` builtin/prototype
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `flash.display.Sprite`'s constructor.
|
/// Implements `flash.display.Sprite`'s instance constructor.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,12 +18,28 @@ pub fn constructor<'gc>(
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `Sprite.prototype`.
|
/// Implements `flash.display.Sprite`'s class constructor.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
// TODO: Use `StageObject` here.
|
Ok(Value::Undefined)
|
||||||
ScriptObject::object(mc, super_proto)
|
}
|
||||||
|
|
||||||
|
/// Construct `Sprite`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(Namespace::package("flash.display"), "Sprite"),
|
||||||
|
Some(
|
||||||
|
QName::new(
|
||||||
|
Namespace::package("flash.display"),
|
||||||
|
"DisplayObjectContainer",
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `flash.events.EventDispatcher` builtin/prototype
|
//! `flash.events.EventDispatcher` builtin/prototype
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `flash.events.EventDispatcher`'s constructor.
|
/// Implements `flash.events.EventDispatcher`'s instance constructor.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,12 +18,22 @@ pub fn constructor<'gc>(
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `EventDispatcher.prototype`.
|
/// Implements `flash.events.EventDispatcher`'s class constructor.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
// TODO: Use `StageObject` here.
|
Ok(Value::Undefined)
|
||||||
ScriptObject::object(mc, super_proto)
|
}
|
||||||
|
|
||||||
|
/// Construct `EventDispatcher`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(Namespace::package("flash.events"), "EventDispatcher"),
|
||||||
|
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,25 @@
|
||||||
//! Function builtin and prototype
|
//! Function builtin and prototype
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
use crate::avm2::names::{Namespace, QName};
|
use crate::avm2::names::{Namespace, QName};
|
||||||
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
|
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
|
||||||
|
use crate::avm2::scope::Scope;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
|
||||||
|
|
||||||
/// Implements `Function`
|
/// Implements `Function`'s instance initializer.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
_this: Option<Object<'gc>>,
|
||||||
|
_args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error> {
|
||||||
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements `Function`'s class initializer.
|
||||||
|
pub fn class_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -38,22 +49,42 @@ fn call<'gc>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Partially construct `Function.prototype`.
|
/// Construct `Function` and `Function.prototype`, respectively.
|
||||||
///
|
pub fn create_class<'gc>(
|
||||||
/// `__proto__` and other cross-linked properties of this object will *not*
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
/// be defined here. The caller of this function is responsible for linking
|
proto: Object<'gc>,
|
||||||
/// them in order to obtain a valid ECMAScript `Function` prototype. The
|
) -> (Object<'gc>, Object<'gc>) {
|
||||||
/// returned object is also a bare object, which will need to be linked into
|
let function_class = Class::new(
|
||||||
/// the prototype of `Object`.
|
QName::new(Namespace::public_namespace(), "Function"),
|
||||||
pub fn create_proto<'gc>(gc_context: MutationContext<'gc, '_>, proto: Object<'gc>) -> Object<'gc> {
|
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||||
let mut function_proto = ScriptObject::object(gc_context, proto);
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
function_proto.install_method(
|
activation.context.gc_context,
|
||||||
gc_context,
|
|
||||||
QName::new(Namespace::as3_namespace(), "call"),
|
|
||||||
0,
|
|
||||||
FunctionObject::from_builtin(gc_context, call, function_proto),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
function_proto
|
let globals = activation.avm2().globals();
|
||||||
|
let scope = Scope::push_scope(globals.get_scope(), globals, activation.context.gc_context);
|
||||||
|
let mut function_proto = ScriptObject::prototype(
|
||||||
|
activation.context.gc_context,
|
||||||
|
proto,
|
||||||
|
function_class,
|
||||||
|
Some(scope),
|
||||||
|
);
|
||||||
|
|
||||||
|
function_proto.install_method(
|
||||||
|
activation.context.gc_context,
|
||||||
|
QName::new(Namespace::as3_namespace(), "call"),
|
||||||
|
0,
|
||||||
|
FunctionObject::from_builtin(activation.context.gc_context, call, function_proto),
|
||||||
|
);
|
||||||
|
|
||||||
|
let constr = FunctionObject::from_builtin_constr(
|
||||||
|
activation.context.gc_context,
|
||||||
|
instance_init,
|
||||||
|
proto,
|
||||||
|
function_proto,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
(constr, function_proto)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `int` impl
|
//! `int` impl
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `int`
|
/// Implements `int`'s instance initializer.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
||||||
Err("int constructor is a stub.".into())
|
Err("int constructor is a stub.".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `int.prototype`.
|
/// Implements `int`'s class initializer.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
ScriptObject::object(mc, super_proto)
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct `int`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(Namespace::package(""), "int"),
|
||||||
|
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `Namespace` impl
|
//! `Namespace` impl
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `Namespace`
|
/// Implements `Namespace`'s instance initializer.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
||||||
Err("Namespace constructor is a stub.".into())
|
Err("Namespace constructor is a stub.".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `Namespace.prototype`.
|
/// Implements `Namespace`'s class initializer.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
ScriptObject::object(mc, super_proto)
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct `Namespace`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(Namespace::package(""), "Namespace"),
|
||||||
|
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `Number` impl
|
//! `Number` impl
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `Number`
|
/// Implements `Number`'s instance initializer.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
||||||
Err("Number constructor is a stub.".into())
|
Err("Number constructor is a stub.".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `Number.prototype`.
|
/// Implements `Number`'s class initializer.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
ScriptObject::object(mc, super_proto)
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct `Number`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(Namespace::package(""), "Number"),
|
||||||
|
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,26 @@
|
||||||
//! Object builtin and prototype
|
//! Object builtin and prototype
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
use crate::avm2::names::{Namespace, QName};
|
use crate::avm2::names::{Namespace, QName};
|
||||||
use crate::avm2::object::{FunctionObject, Object, TObject};
|
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
|
||||||
|
use crate::avm2::scope::Scope;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::MutationContext;
|
||||||
|
|
||||||
/// Implements `Object`
|
/// Implements `Object`'s instance initializer.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
_this: Option<Object<'gc>>,
|
||||||
|
_args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error> {
|
||||||
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements `Object`'s class initializer
|
||||||
|
pub fn class_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -140,7 +152,26 @@ pub fn set_property_is_enumerable<'gc>(
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Partially construct `Object.prototype`.
|
/// Create object prototype.
|
||||||
|
///
|
||||||
|
/// This function creates a suitable class and object prototype attached to it,
|
||||||
|
/// but does not actually fill it with methods. That requires a valid function
|
||||||
|
/// prototype, and is thus done by `fill_proto` below.
|
||||||
|
pub fn create_proto<'gc>(activation: &mut Activation<'_, 'gc, '_>) -> Object<'gc> {
|
||||||
|
let object_class = Class::new(
|
||||||
|
QName::new(Namespace::public_namespace(), "Object"),
|
||||||
|
None,
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
activation.context.gc_context,
|
||||||
|
);
|
||||||
|
|
||||||
|
let globals = activation.avm2().globals();
|
||||||
|
let scope = Scope::push_scope(globals.get_scope(), globals, activation.context.gc_context);
|
||||||
|
ScriptObject::bare_prototype(activation.context.gc_context, object_class, Some(scope))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finish constructing `Object.prototype`, and also construct `Object`.
|
||||||
///
|
///
|
||||||
/// `__proto__` and other cross-linked properties of this object will *not*
|
/// `__proto__` and other cross-linked properties of this object will *not*
|
||||||
/// be defined here. The caller of this function is responsible for linking
|
/// be defined here. The caller of this function is responsible for linking
|
||||||
|
@ -153,7 +184,7 @@ pub fn fill_proto<'gc>(
|
||||||
gc_context: MutationContext<'gc, '_>,
|
gc_context: MutationContext<'gc, '_>,
|
||||||
mut object_proto: Object<'gc>,
|
mut object_proto: Object<'gc>,
|
||||||
fn_proto: Object<'gc>,
|
fn_proto: Object<'gc>,
|
||||||
) {
|
) -> Object<'gc> {
|
||||||
object_proto.install_method(
|
object_proto.install_method(
|
||||||
gc_context,
|
gc_context,
|
||||||
QName::new(Namespace::public_namespace(), "toString"),
|
QName::new(Namespace::public_namespace(), "toString"),
|
||||||
|
@ -196,4 +227,6 @@ pub fn fill_proto<'gc>(
|
||||||
0,
|
0,
|
||||||
FunctionObject::from_builtin(gc_context, set_property_is_enumerable, fn_proto),
|
FunctionObject::from_builtin(gc_context, set_property_is_enumerable, fn_proto),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
FunctionObject::from_builtin_constr(gc_context, instance_init, object_proto, fn_proto).unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `String` impl
|
//! `String` impl
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `String`
|
/// Implements `String`'s instance initializer.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
||||||
Err("String constructor is a stub.".into())
|
Err("String constructor is a stub.".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `String.prototype`.
|
/// Implements `String`'s class initializer.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
ScriptObject::object(mc, super_proto)
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct `String`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(Namespace::package(""), "String"),
|
||||||
|
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
//! `uint` impl
|
//! `uint` impl
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::object::{Object, ScriptObject};
|
use crate::avm2::class::Class;
|
||||||
|
use crate::avm2::method::Method;
|
||||||
|
use crate::avm2::names::{Namespace, QName};
|
||||||
|
use crate::avm2::object::Object;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::{GcCell, MutationContext};
|
||||||
|
|
||||||
/// Implements `uint`
|
/// Implements `uint`'s instance initializer.
|
||||||
pub fn constructor<'gc>(
|
pub fn instance_init<'gc>(
|
||||||
_activation: &mut Activation<'_, 'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
_this: Option<Object<'gc>>,
|
_this: Option<Object<'gc>>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
||||||
Err("uint constructor is a stub.".into())
|
Err("uint constructor is a stub.".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct `uint.prototype`.
|
/// Implements `uint`'s class initializer.
|
||||||
pub fn create_proto<'gc>(
|
pub fn class_init<'gc>(
|
||||||
mc: MutationContext<'gc, '_>,
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
super_proto: Object<'gc>,
|
_this: Option<Object<'gc>>,
|
||||||
_fn_proto: Object<'gc>,
|
_args: &[Value<'gc>],
|
||||||
) -> Object<'gc> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
ScriptObject::object(mc, super_proto)
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct `uint`'s class.
|
||||||
|
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||||
|
Class::new(
|
||||||
|
QName::new(Namespace::package(""), "uint"),
|
||||||
|
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||||
|
Method::from_builtin(instance_init),
|
||||||
|
Method::from_builtin(class_init),
|
||||||
|
mc,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,12 @@ use crate::avm2::object::Object;
|
||||||
use crate::avm2::script::TranslationUnit;
|
use crate::avm2::script::TranslationUnit;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
|
use crate::collect::CollectWrapper;
|
||||||
use gc_arena::{Collect, CollectionContext, Gc, MutationContext};
|
use gc_arena::{Collect, CollectionContext, Gc, MutationContext};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use swf::avm2::types::{AbcFile, Index, Method as AbcMethod, MethodBody as AbcMethodBody};
|
use swf::avm2::types::{AbcFile, Index, Method as AbcMethod, MethodBody as AbcMethodBody};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Collect)]
|
|
||||||
#[collect(require_static)]
|
|
||||||
pub struct CollectWrapper<T>(T);
|
|
||||||
|
|
||||||
/// Represents a function defined in Ruffle's code.
|
/// Represents a function defined in Ruffle's code.
|
||||||
///
|
///
|
||||||
/// Parameters are as follows:
|
/// Parameters are as follows:
|
||||||
|
@ -162,6 +159,12 @@ impl<'gc> From<Gc<'gc, BytecodeMethod<'gc>>> for Method<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> Method<'gc> {
|
impl<'gc> Method<'gc> {
|
||||||
|
/// Builtin method constructor, because for some reason `nf.into()` just
|
||||||
|
/// causes odd lifetime mismatches.
|
||||||
|
pub fn from_builtin(nf: NativeMethod<'gc>) -> Self {
|
||||||
|
Self::Native(nf)
|
||||||
|
}
|
||||||
|
|
||||||
/// Access the bytecode of this method.
|
/// Access the bytecode of this method.
|
||||||
///
|
///
|
||||||
/// This function returns `Err` if there is no bytecode for this method.
|
/// This function returns `Err` if there is no bytecode for this method.
|
||||||
|
|
|
@ -357,3 +357,12 @@ impl<'gc> Multiname<'gc> {
|
||||||
self.name
|
self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'gc> From<QName<'gc>> for Multiname<'gc> {
|
||||||
|
fn from(q: QName<'gc>) -> Self {
|
||||||
|
Self {
|
||||||
|
ns: vec![q.ns],
|
||||||
|
name: Some(q.name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::class::Class;
|
use crate::avm2::class::Class;
|
||||||
use crate::avm2::function::Executable;
|
use crate::avm2::function::Executable;
|
||||||
use crate::avm2::names::{Multiname, Namespace, QName};
|
use crate::avm2::names::{Multiname, Namespace, QName};
|
||||||
use crate::avm2::r#trait::{Trait, TraitKind};
|
|
||||||
use crate::avm2::scope::Scope;
|
use crate::avm2::scope::Scope;
|
||||||
use crate::avm2::string::AvmString;
|
use crate::avm2::string::AvmString;
|
||||||
|
use crate::avm2::traits::{Trait, TraitKind};
|
||||||
use crate::avm2::value::{Hint, Value};
|
use crate::avm2::value::{Hint, Value};
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
|
@ -415,23 +415,29 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
/// bound to. It should always be `self` except when doing things with
|
/// bound to. It should always be `self` except when doing things with
|
||||||
/// `super`, which needs to create bound methods pointing to a different
|
/// `super`, which needs to create bound methods pointing to a different
|
||||||
/// object.
|
/// object.
|
||||||
|
///
|
||||||
|
/// The value of the trait at the time of installation will be returned
|
||||||
|
/// here.
|
||||||
fn install_trait(
|
fn install_trait(
|
||||||
&mut self,
|
&mut self,
|
||||||
activation: &mut Activation<'_, 'gc, '_>,
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
trait_entry: Trait<'gc>,
|
trait_entry: Trait<'gc>,
|
||||||
reciever: Object<'gc>,
|
reciever: Object<'gc>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
self.install_foreign_trait(activation, trait_entry, self.get_scope(), reciever)
|
self.install_foreign_trait(activation, trait_entry, self.get_scope(), reciever)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Install a trait from anywyere.
|
/// Install a trait from anywyere.
|
||||||
|
///
|
||||||
|
/// The value of the trait at the time of installation will be returned
|
||||||
|
/// here.
|
||||||
fn install_foreign_trait(
|
fn install_foreign_trait(
|
||||||
&mut self,
|
&mut self,
|
||||||
activation: &mut Activation<'_, 'gc, '_>,
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
trait_entry: Trait<'gc>,
|
trait_entry: Trait<'gc>,
|
||||||
scope: Option<GcCell<'gc, Scope<'gc>>>,
|
scope: Option<GcCell<'gc, Scope<'gc>>>,
|
||||||
reciever: Object<'gc>,
|
reciever: Object<'gc>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
let fn_proto = activation.avm2().prototypes().function;
|
let fn_proto = activation.avm2().prototypes().function;
|
||||||
let trait_name = trait_entry.name().clone();
|
let trait_name = trait_entry.name().clone();
|
||||||
avm_debug!(
|
avm_debug!(
|
||||||
|
@ -447,12 +453,15 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
default_value,
|
default_value,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
let value = default_value.clone().unwrap_or(Value::Undefined);
|
||||||
self.install_slot(
|
self.install_slot(
|
||||||
activation.context.gc_context,
|
activation.context.gc_context,
|
||||||
trait_name,
|
trait_name,
|
||||||
*slot_id,
|
*slot_id,
|
||||||
default_value.clone().unwrap_or(Value::Undefined),
|
value.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
}
|
}
|
||||||
TraitKind::Method {
|
TraitKind::Method {
|
||||||
disp_id, method, ..
|
disp_id, method, ..
|
||||||
|
@ -470,6 +479,8 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
*disp_id,
|
*disp_id,
|
||||||
function,
|
function,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(function.into())
|
||||||
}
|
}
|
||||||
TraitKind::Getter {
|
TraitKind::Getter {
|
||||||
disp_id, method, ..
|
disp_id, method, ..
|
||||||
|
@ -487,6 +498,8 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
*disp_id,
|
*disp_id,
|
||||||
function,
|
function,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
Ok(function.into())
|
||||||
}
|
}
|
||||||
TraitKind::Setter {
|
TraitKind::Setter {
|
||||||
disp_id, method, ..
|
disp_id, method, ..
|
||||||
|
@ -504,6 +517,8 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
*disp_id,
|
*disp_id,
|
||||||
function,
|
function,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
Ok(function.into())
|
||||||
}
|
}
|
||||||
TraitKind::Class { slot_id, class } => {
|
TraitKind::Class { slot_id, class } => {
|
||||||
let class_read = class.read();
|
let class_read = class.read();
|
||||||
|
@ -533,6 +548,8 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
*slot_id,
|
*slot_id,
|
||||||
class_object.into(),
|
class_object.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(class_object.into())
|
||||||
}
|
}
|
||||||
TraitKind::Function {
|
TraitKind::Function {
|
||||||
slot_id, function, ..
|
slot_id, function, ..
|
||||||
|
@ -561,22 +578,25 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
*slot_id,
|
*slot_id,
|
||||||
fobject.into(),
|
fobject.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(fobject.into())
|
||||||
}
|
}
|
||||||
TraitKind::Const {
|
TraitKind::Const {
|
||||||
slot_id,
|
slot_id,
|
||||||
default_value,
|
default_value,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
let value = default_value.clone().unwrap_or(Value::Undefined);
|
||||||
self.install_const(
|
self.install_const(
|
||||||
activation.context.gc_context,
|
activation.context.gc_context,
|
||||||
trait_name,
|
trait_name,
|
||||||
*slot_id,
|
*slot_id,
|
||||||
default_value.clone().unwrap_or(Value::Undefined),
|
value.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the object.
|
/// Call the object.
|
||||||
|
@ -703,6 +723,9 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
/// Get a raw pointer value for this object.
|
/// Get a raw pointer value for this object.
|
||||||
fn as_ptr(&self) -> *const ObjectPtr;
|
fn as_ptr(&self) -> *const ObjectPtr;
|
||||||
|
|
||||||
|
/// Get this object's `Class`, if it has one.
|
||||||
|
fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>>;
|
||||||
|
|
||||||
/// Get this object's `Executable`, if it has one.
|
/// Get this object's `Executable`, if it has one.
|
||||||
fn as_executable(&self) -> Option<Executable<'gc>> {
|
fn as_executable(&self) -> Option<Executable<'gc>> {
|
||||||
None
|
None
|
||||||
|
|
|
@ -179,6 +179,10 @@ macro_rules! impl_avm2_custom_object {
|
||||||
self.0.as_ptr() as *const ObjectPtr
|
self.0.as_ptr() as *const ObjectPtr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>> {
|
||||||
|
self.0.read().base.as_class()
|
||||||
|
}
|
||||||
|
|
||||||
fn install_method(
|
fn install_method(
|
||||||
&mut self,
|
&mut self,
|
||||||
mc: MutationContext<'gc, '_>,
|
mc: MutationContext<'gc, '_>,
|
||||||
|
|
|
@ -7,9 +7,9 @@ use crate::avm2::method::{Method, NativeMethod};
|
||||||
use crate::avm2::names::{Namespace, QName};
|
use crate::avm2::names::{Namespace, QName};
|
||||||
use crate::avm2::object::script_object::{ScriptObject, ScriptObjectClass, ScriptObjectData};
|
use crate::avm2::object::script_object::{ScriptObject, ScriptObjectClass, ScriptObjectData};
|
||||||
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
||||||
use crate::avm2::r#trait::Trait;
|
|
||||||
use crate::avm2::scope::Scope;
|
use crate::avm2::scope::Scope;
|
||||||
use crate::avm2::string::AvmString;
|
use crate::avm2::string::AvmString;
|
||||||
|
use crate::avm2::traits::Trait;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use crate::impl_avm2_custom_object;
|
use crate::impl_avm2_custom_object;
|
||||||
|
@ -195,10 +195,15 @@ impl<'gc> FunctionObject<'gc> {
|
||||||
mut prototype: Object<'gc>,
|
mut prototype: Object<'gc>,
|
||||||
fn_proto: Object<'gc>,
|
fn_proto: Object<'gc>,
|
||||||
) -> Result<Object<'gc>, Error> {
|
) -> Result<Object<'gc>, Error> {
|
||||||
|
let scope = prototype.get_scope();
|
||||||
|
let class = prototype
|
||||||
|
.as_class()
|
||||||
|
.map(|c| ScriptObjectClass::ClassConstructor(c, scope))
|
||||||
|
.unwrap_or(ScriptObjectClass::NoClass);
|
||||||
let mut base: Object<'gc> = FunctionObject(GcCell::allocate(
|
let mut base: Object<'gc> = FunctionObject(GcCell::allocate(
|
||||||
mc,
|
mc,
|
||||||
FunctionObjectData {
|
FunctionObjectData {
|
||||||
base: ScriptObjectData::base_new(Some(fn_proto), ScriptObjectClass::NoClass),
|
base: ScriptObjectData::base_new(Some(fn_proto), class),
|
||||||
exec: Some(Executable::from_method(constr.into(), None, None, mc)),
|
exec: Some(Executable::from_method(constr.into(), None, None, mc)),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
|
|
@ -6,8 +6,8 @@ use crate::avm2::class::Class;
|
||||||
use crate::avm2::names::{Namespace, QName};
|
use crate::avm2::names::{Namespace, QName};
|
||||||
use crate::avm2::object::script_object::{ScriptObjectClass, ScriptObjectData};
|
use crate::avm2::object::script_object::{ScriptObjectClass, ScriptObjectData};
|
||||||
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
||||||
use crate::avm2::r#trait::Trait;
|
|
||||||
use crate::avm2::scope::Scope;
|
use crate::avm2::scope::Scope;
|
||||||
|
use crate::avm2::traits::Trait;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use crate::impl_avm2_custom_object;
|
use crate::impl_avm2_custom_object;
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::class::Class;
|
use crate::avm2::class::Class;
|
||||||
use crate::avm2::function::Executable;
|
|
||||||
use crate::avm2::names::{Namespace, QName};
|
use crate::avm2::names::{Namespace, QName};
|
||||||
use crate::avm2::object::script_object::{ScriptObjectClass, ScriptObjectData};
|
use crate::avm2::object::script_object::{ScriptObjectClass, ScriptObjectData};
|
||||||
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
||||||
use crate::avm2::r#trait::Trait;
|
|
||||||
use crate::avm2::scope::Scope;
|
use crate::avm2::scope::Scope;
|
||||||
use crate::avm2::string::AvmString;
|
use crate::avm2::string::AvmString;
|
||||||
|
use crate::avm2::traits::Trait;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
|
use crate::impl_avm2_custom_object;
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
|
|
||||||
/// An Object which represents a primitive value of some other kind.
|
/// An Object which represents a primitive value of some other kind.
|
||||||
|
@ -50,181 +50,14 @@ impl<'gc> PrimitiveObject<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> TObject<'gc> for PrimitiveObject<'gc> {
|
impl<'gc> TObject<'gc> for PrimitiveObject<'gc> {
|
||||||
fn get_property_local(
|
impl_avm2_custom_object!(base);
|
||||||
self,
|
|
||||||
reciever: Object<'gc>,
|
|
||||||
name: &QName<'gc>,
|
|
||||||
activation: &mut Activation<'_, 'gc, '_>,
|
|
||||||
) -> Result<Value<'gc>, Error> {
|
|
||||||
let read = self.0.read();
|
|
||||||
let rv = read.base.get_property_local(reciever, name, activation)?;
|
|
||||||
|
|
||||||
drop(read);
|
fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
|
||||||
|
Ok(self.0.read().primitive.clone())
|
||||||
rv.resolve(activation)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_property_local(
|
fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
|
||||||
self,
|
Ok(self.0.read().primitive.clone())
|
||||||
reciever: Object<'gc>,
|
|
||||||
name: &QName<'gc>,
|
|
||||||
value: Value<'gc>,
|
|
||||||
activation: &mut Activation<'_, 'gc, '_>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let mut write = self.0.write(activation.context.gc_context);
|
|
||||||
let rv = write
|
|
||||||
.base
|
|
||||||
.set_property_local(reciever, name, value, activation)?;
|
|
||||||
|
|
||||||
drop(write);
|
|
||||||
|
|
||||||
rv.resolve(activation)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_property_local(
|
|
||||||
self,
|
|
||||||
reciever: Object<'gc>,
|
|
||||||
name: &QName<'gc>,
|
|
||||||
value: Value<'gc>,
|
|
||||||
activation: &mut Activation<'_, 'gc, '_>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let mut write = self.0.write(activation.context.gc_context);
|
|
||||||
let rv = write
|
|
||||||
.base
|
|
||||||
.init_property_local(reciever, name, value, activation)?;
|
|
||||||
|
|
||||||
drop(write);
|
|
||||||
|
|
||||||
rv.resolve(activation)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_property_overwritable(
|
|
||||||
self,
|
|
||||||
gc_context: MutationContext<'gc, '_>,
|
|
||||||
name: &QName<'gc>,
|
|
||||||
) -> bool {
|
|
||||||
self.0.write(gc_context).base.is_property_overwritable(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_property(
|
|
||||||
&self,
|
|
||||||
gc_context: MutationContext<'gc, '_>,
|
|
||||||
multiname: &QName<'gc>,
|
|
||||||
) -> bool {
|
|
||||||
self.0.write(gc_context).base.delete_property(multiname)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_slot(self, id: u32) -> Result<Value<'gc>, Error> {
|
|
||||||
self.0.read().base.get_slot(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_slot(
|
|
||||||
self,
|
|
||||||
id: u32,
|
|
||||||
value: Value<'gc>,
|
|
||||||
mc: MutationContext<'gc, '_>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.0.write(mc).base.set_slot(id, value, mc)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_slot(
|
|
||||||
self,
|
|
||||||
id: u32,
|
|
||||||
value: Value<'gc>,
|
|
||||||
mc: MutationContext<'gc, '_>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.0.write(mc).base.init_slot(id, value, mc)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_method(self, id: u32) -> Option<Object<'gc>> {
|
|
||||||
self.0.read().base.get_method(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_trait(self, name: &QName<'gc>) -> Result<Vec<Trait<'gc>>, Error> {
|
|
||||||
self.0.read().base.get_trait(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_provided_trait(
|
|
||||||
&self,
|
|
||||||
name: &QName<'gc>,
|
|
||||||
known_traits: &mut Vec<Trait<'gc>>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.0.read().base.get_provided_trait(name, known_traits)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_scope(self) -> Option<GcCell<'gc, Scope<'gc>>> {
|
|
||||||
self.0.read().base.get_scope()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_any(self, local_name: AvmString<'gc>) -> Result<Option<Namespace<'gc>>, Error> {
|
|
||||||
self.0.read().base.resolve_any(local_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_any_trait(
|
|
||||||
self,
|
|
||||||
local_name: AvmString<'gc>,
|
|
||||||
) -> Result<Option<Namespace<'gc>>, Error> {
|
|
||||||
self.0.read().base.resolve_any_trait(local_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> {
|
|
||||||
self.0.read().base.has_own_property(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_trait(self, name: &QName<'gc>) -> Result<bool, Error> {
|
|
||||||
self.0.read().base.has_trait(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn provides_trait(self, name: &QName<'gc>) -> Result<bool, Error> {
|
|
||||||
self.0.read().base.provides_trait(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_instantiated_property(self, name: &QName<'gc>) -> bool {
|
|
||||||
self.0.read().base.has_instantiated_property(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_own_virtual_getter(self, name: &QName<'gc>) -> bool {
|
|
||||||
self.0.read().base.has_own_virtual_getter(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_own_virtual_setter(self, name: &QName<'gc>) -> bool {
|
|
||||||
self.0.read().base.has_own_virtual_setter(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn proto(&self) -> Option<Object<'gc>> {
|
|
||||||
self.0.read().base.proto()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_enumerant_name(&self, index: u32) -> Option<QName<'gc>> {
|
|
||||||
self.0.read().base.get_enumerant_name(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn property_is_enumerable(&self, name: &QName<'gc>) -> bool {
|
|
||||||
self.0.read().base.property_is_enumerable(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_local_property_is_enumerable(
|
|
||||||
&self,
|
|
||||||
mc: MutationContext<'gc, '_>,
|
|
||||||
name: &QName<'gc>,
|
|
||||||
is_enumerable: bool,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.0
|
|
||||||
.write(mc)
|
|
||||||
.base
|
|
||||||
.set_local_property_is_enumerable(name, is_enumerable)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_ptr(&self) -> *const ObjectPtr {
|
|
||||||
self.0.as_ptr() as *const ObjectPtr
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_executable(&self) -> Option<Executable<'gc>> {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct(
|
fn construct(
|
||||||
|
@ -266,88 +99,4 @@ impl<'gc> TObject<'gc> for PrimitiveObject<'gc> {
|
||||||
))
|
))
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
|
|
||||||
Ok(self.0.read().primitive.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
|
|
||||||
Ok(self.0.read().primitive.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn install_method(
|
|
||||||
&mut self,
|
|
||||||
mc: MutationContext<'gc, '_>,
|
|
||||||
name: QName<'gc>,
|
|
||||||
disp_id: u32,
|
|
||||||
function: Object<'gc>,
|
|
||||||
) {
|
|
||||||
self.0
|
|
||||||
.write(mc)
|
|
||||||
.base
|
|
||||||
.install_method(name, disp_id, function)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn install_getter(
|
|
||||||
&mut self,
|
|
||||||
mc: MutationContext<'gc, '_>,
|
|
||||||
name: QName<'gc>,
|
|
||||||
disp_id: u32,
|
|
||||||
function: Object<'gc>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.0
|
|
||||||
.write(mc)
|
|
||||||
.base
|
|
||||||
.install_getter(name, disp_id, function)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn install_setter(
|
|
||||||
&mut self,
|
|
||||||
mc: MutationContext<'gc, '_>,
|
|
||||||
name: QName<'gc>,
|
|
||||||
disp_id: u32,
|
|
||||||
function: Object<'gc>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.0
|
|
||||||
.write(mc)
|
|
||||||
.base
|
|
||||||
.install_setter(name, disp_id, function)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn install_dynamic_property(
|
|
||||||
&mut self,
|
|
||||||
mc: MutationContext<'gc, '_>,
|
|
||||||
name: QName<'gc>,
|
|
||||||
value: Value<'gc>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.0.write(mc).base.install_dynamic_property(name, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn install_slot(
|
|
||||||
&mut self,
|
|
||||||
mc: MutationContext<'gc, '_>,
|
|
||||||
name: QName<'gc>,
|
|
||||||
id: u32,
|
|
||||||
value: Value<'gc>,
|
|
||||||
) {
|
|
||||||
self.0.write(mc).base.install_slot(name, id, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn install_const(
|
|
||||||
&mut self,
|
|
||||||
mc: MutationContext<'gc, '_>,
|
|
||||||
name: QName<'gc>,
|
|
||||||
id: u32,
|
|
||||||
value: Value<'gc>,
|
|
||||||
) {
|
|
||||||
self.0.write(mc).base.install_const(name, id, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn interfaces(&self) -> Vec<Object<'gc>> {
|
|
||||||
self.0.read().base.interfaces()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_interfaces(&self, context: MutationContext<'gc, '_>, iface_list: Vec<Object<'gc>>) {
|
|
||||||
self.0.write(context).base.set_interfaces(iface_list)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,11 @@ use crate::avm2::names::{Namespace, QName};
|
||||||
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
||||||
use crate::avm2::property::Property;
|
use crate::avm2::property::Property;
|
||||||
use crate::avm2::property_map::PropertyMap;
|
use crate::avm2::property_map::PropertyMap;
|
||||||
use crate::avm2::r#trait::Trait;
|
|
||||||
use crate::avm2::return_value::ReturnValue;
|
use crate::avm2::return_value::ReturnValue;
|
||||||
use crate::avm2::scope::Scope;
|
use crate::avm2::scope::Scope;
|
||||||
use crate::avm2::slot::Slot;
|
use crate::avm2::slot::Slot;
|
||||||
use crate::avm2::string::AvmString;
|
use crate::avm2::string::AvmString;
|
||||||
|
use crate::avm2::traits::Trait;
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::Error;
|
use crate::avm2::Error;
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
|
@ -337,6 +337,10 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
|
||||||
fn set_interfaces(&self, context: MutationContext<'gc, '_>, iface_list: Vec<Object<'gc>>) {
|
fn set_interfaces(&self, context: MutationContext<'gc, '_>, iface_list: Vec<Object<'gc>>) {
|
||||||
self.0.write(context).set_interfaces(iface_list)
|
self.0.write(context).set_interfaces(iface_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>> {
|
||||||
|
self.0.read().as_class()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> ScriptObject<'gc> {
|
impl<'gc> ScriptObject<'gc> {
|
||||||
|
@ -897,4 +901,13 @@ impl<'gc> ScriptObjectData<'gc> {
|
||||||
pub fn set_interfaces(&mut self, iface_list: Vec<Object<'gc>>) {
|
pub fn set_interfaces(&mut self, iface_list: Vec<Object<'gc>>) {
|
||||||
self.interfaces = iface_list;
|
self.interfaces = iface_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the class for this object, if it has one.
|
||||||
|
pub fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>> {
|
||||||
|
match self.class {
|
||||||
|
ScriptObjectClass::ClassConstructor(class, _) => Some(class),
|
||||||
|
ScriptObjectClass::InstancePrototype(class, _) => Some(class),
|
||||||
|
ScriptObjectClass::NoClass => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,16 @@
|
||||||
|
|
||||||
use crate::avm2::class::Class;
|
use crate::avm2::class::Class;
|
||||||
use crate::avm2::method::{BytecodeMethod, Method};
|
use crate::avm2::method::{BytecodeMethod, Method};
|
||||||
use crate::avm2::r#trait::Trait;
|
|
||||||
use crate::avm2::string::AvmString;
|
use crate::avm2::string::AvmString;
|
||||||
|
use crate::avm2::traits::Trait;
|
||||||
use crate::avm2::{Avm2, Error};
|
use crate::avm2::{Avm2, Error};
|
||||||
|
use crate::collect::CollectWrapper;
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use gc_arena::{Collect, Gc, GcCell, MutationContext};
|
use gc_arena::{Collect, Gc, GcCell, MutationContext};
|
||||||
use std::mem::drop;
|
use std::mem::drop;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use swf::avm2::types::{AbcFile, Index, Script as AbcScript};
|
use swf::avm2::types::{AbcFile, Index, Script as AbcScript};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Collect)]
|
|
||||||
#[collect(require_static)]
|
|
||||||
pub struct CollectWrapper<T>(T);
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Collect)]
|
#[derive(Copy, Clone, Debug, Collect)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
pub struct TranslationUnit<'gc>(GcCell<'gc, TranslationUnitData<'gc>>);
|
pub struct TranslationUnit<'gc>(GcCell<'gc, TranslationUnitData<'gc>>);
|
||||||
|
|
|
@ -6,9 +6,23 @@ use crate::avm2::names::{Multiname, QName};
|
||||||
use crate::avm2::script::TranslationUnit;
|
use crate::avm2::script::TranslationUnit;
|
||||||
use crate::avm2::value::{abc_default_value, Value};
|
use crate::avm2::value::{abc_default_value, Value};
|
||||||
use crate::avm2::{Avm2, Error};
|
use crate::avm2::{Avm2, Error};
|
||||||
|
use crate::collect::CollectWrapper;
|
||||||
|
use enumset::{EnumSet, EnumSetType};
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
use swf::avm2::types::{Trait as AbcTrait, TraitKind as AbcTraitKind};
|
use swf::avm2::types::{Trait as AbcTrait, TraitKind as AbcTraitKind};
|
||||||
|
|
||||||
|
/// All attributes a trait can have.
|
||||||
|
#[derive(Debug, EnumSetType)]
|
||||||
|
pub enum TraitAttributes {
|
||||||
|
/// Whether or not traits in downstream classes are allowed to override
|
||||||
|
/// this trait.
|
||||||
|
Final,
|
||||||
|
|
||||||
|
/// Whether or not this trait is intended to override an upstream class's
|
||||||
|
/// trait.
|
||||||
|
Override,
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a trait as loaded into the VM.
|
/// Represents a trait as loaded into the VM.
|
||||||
///
|
///
|
||||||
/// A trait is an uninstantiated AVM2 property. Traits are used by objects to
|
/// A trait is an uninstantiated AVM2 property. Traits are used by objects to
|
||||||
|
@ -25,18 +39,22 @@ pub struct Trait<'gc> {
|
||||||
/// The name of this trait.
|
/// The name of this trait.
|
||||||
name: QName<'gc>,
|
name: QName<'gc>,
|
||||||
|
|
||||||
/// Whether or not traits in downstream classes are allowed to override
|
/// The attributes set on this trait.
|
||||||
/// this trait.
|
attributes: CollectWrapper<EnumSet<TraitAttributes>>,
|
||||||
is_final: bool,
|
|
||||||
|
|
||||||
/// Whether or not this trait is intended to override an upstream class's
|
|
||||||
/// trait.
|
|
||||||
is_override: bool,
|
|
||||||
|
|
||||||
/// The kind of trait in use.
|
/// The kind of trait in use.
|
||||||
kind: TraitKind<'gc>,
|
kind: TraitKind<'gc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn trait_attribs_from_abc_traits(abc_trait: &AbcTrait) -> CollectWrapper<EnumSet<TraitAttributes>> {
|
||||||
|
CollectWrapper(match (abc_trait.is_final, abc_trait.is_override) {
|
||||||
|
(true, true) => TraitAttributes::Final | TraitAttributes::Override,
|
||||||
|
(true, false) => TraitAttributes::Final.into(),
|
||||||
|
(false, true) => TraitAttributes::Override.into(),
|
||||||
|
(false, false) => EnumSet::empty(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// The fields for a particular kind of trait.
|
/// The fields for a particular kind of trait.
|
||||||
///
|
///
|
||||||
/// The kind of a trait also determines how it's instantiated on the object.
|
/// The kind of a trait also determines how it's instantiated on the object.
|
||||||
|
@ -81,6 +99,83 @@ pub enum TraitKind<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> Trait<'gc> {
|
impl<'gc> Trait<'gc> {
|
||||||
|
pub fn from_class(class: GcCell<'gc, Class<'gc>>) -> Self {
|
||||||
|
let name = class.read().name().clone();
|
||||||
|
|
||||||
|
Trait {
|
||||||
|
name,
|
||||||
|
attributes: CollectWrapper(EnumSet::empty()),
|
||||||
|
kind: TraitKind::Class { slot_id: 0, class },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_method(name: QName<'gc>, method: Method<'gc>) -> Self {
|
||||||
|
Trait {
|
||||||
|
name,
|
||||||
|
attributes: CollectWrapper(EnumSet::empty()),
|
||||||
|
kind: TraitKind::Method { disp_id: 0, method },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_getter(name: QName<'gc>, method: Method<'gc>) -> Self {
|
||||||
|
Trait {
|
||||||
|
name,
|
||||||
|
attributes: CollectWrapper(EnumSet::empty()),
|
||||||
|
kind: TraitKind::Getter { disp_id: 0, method },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_setter(name: QName<'gc>, method: Method<'gc>) -> Self {
|
||||||
|
Trait {
|
||||||
|
name,
|
||||||
|
attributes: CollectWrapper(EnumSet::empty()),
|
||||||
|
kind: TraitKind::Setter { disp_id: 0, method },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_function(name: QName<'gc>, function: Method<'gc>) -> Self {
|
||||||
|
Trait {
|
||||||
|
name,
|
||||||
|
attributes: CollectWrapper(EnumSet::empty()),
|
||||||
|
kind: TraitKind::Function {
|
||||||
|
slot_id: 0,
|
||||||
|
function,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_slot(
|
||||||
|
name: QName<'gc>,
|
||||||
|
type_name: Multiname<'gc>,
|
||||||
|
default_value: Option<Value<'gc>>,
|
||||||
|
) -> Self {
|
||||||
|
Trait {
|
||||||
|
name,
|
||||||
|
attributes: CollectWrapper(EnumSet::empty()),
|
||||||
|
kind: TraitKind::Slot {
|
||||||
|
slot_id: 0,
|
||||||
|
type_name,
|
||||||
|
default_value,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_const(
|
||||||
|
name: QName<'gc>,
|
||||||
|
type_name: Multiname<'gc>,
|
||||||
|
default_value: Option<Value<'gc>>,
|
||||||
|
) -> Self {
|
||||||
|
Trait {
|
||||||
|
name,
|
||||||
|
attributes: CollectWrapper(EnumSet::empty()),
|
||||||
|
kind: TraitKind::Slot {
|
||||||
|
slot_id: 0,
|
||||||
|
type_name,
|
||||||
|
default_value,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert an ABC trait into a loaded trait.
|
/// Convert an ABC trait into a loaded trait.
|
||||||
pub fn from_abc_trait(
|
pub fn from_abc_trait(
|
||||||
unit: TranslationUnit<'gc>,
|
unit: TranslationUnit<'gc>,
|
||||||
|
@ -97,8 +192,7 @@ impl<'gc> Trait<'gc> {
|
||||||
value,
|
value,
|
||||||
} => Trait {
|
} => Trait {
|
||||||
name,
|
name,
|
||||||
is_final: abc_trait.is_final,
|
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||||
is_override: abc_trait.is_override,
|
|
||||||
kind: TraitKind::Slot {
|
kind: TraitKind::Slot {
|
||||||
slot_id: *slot_id,
|
slot_id: *slot_id,
|
||||||
type_name: if type_name.0 == 0 {
|
type_name: if type_name.0 == 0 {
|
||||||
|
@ -115,8 +209,7 @@ impl<'gc> Trait<'gc> {
|
||||||
},
|
},
|
||||||
AbcTraitKind::Method { disp_id, method } => Trait {
|
AbcTraitKind::Method { disp_id, method } => Trait {
|
||||||
name,
|
name,
|
||||||
is_final: abc_trait.is_final,
|
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||||
is_override: abc_trait.is_override,
|
|
||||||
kind: TraitKind::Method {
|
kind: TraitKind::Method {
|
||||||
disp_id: *disp_id,
|
disp_id: *disp_id,
|
||||||
method: unit.load_method(method.0, mc)?,
|
method: unit.load_method(method.0, mc)?,
|
||||||
|
@ -124,8 +217,7 @@ impl<'gc> Trait<'gc> {
|
||||||
},
|
},
|
||||||
AbcTraitKind::Getter { disp_id, method } => Trait {
|
AbcTraitKind::Getter { disp_id, method } => Trait {
|
||||||
name,
|
name,
|
||||||
is_final: abc_trait.is_final,
|
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||||
is_override: abc_trait.is_override,
|
|
||||||
kind: TraitKind::Getter {
|
kind: TraitKind::Getter {
|
||||||
disp_id: *disp_id,
|
disp_id: *disp_id,
|
||||||
method: unit.load_method(method.0, mc)?,
|
method: unit.load_method(method.0, mc)?,
|
||||||
|
@ -133,8 +225,7 @@ impl<'gc> Trait<'gc> {
|
||||||
},
|
},
|
||||||
AbcTraitKind::Setter { disp_id, method } => Trait {
|
AbcTraitKind::Setter { disp_id, method } => Trait {
|
||||||
name,
|
name,
|
||||||
is_final: abc_trait.is_final,
|
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||||
is_override: abc_trait.is_override,
|
|
||||||
kind: TraitKind::Setter {
|
kind: TraitKind::Setter {
|
||||||
disp_id: *disp_id,
|
disp_id: *disp_id,
|
||||||
method: unit.load_method(method.0, mc)?,
|
method: unit.load_method(method.0, mc)?,
|
||||||
|
@ -142,8 +233,7 @@ impl<'gc> Trait<'gc> {
|
||||||
},
|
},
|
||||||
AbcTraitKind::Class { slot_id, class } => Trait {
|
AbcTraitKind::Class { slot_id, class } => Trait {
|
||||||
name,
|
name,
|
||||||
is_final: abc_trait.is_final,
|
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||||
is_override: abc_trait.is_override,
|
|
||||||
kind: TraitKind::Class {
|
kind: TraitKind::Class {
|
||||||
slot_id: *slot_id,
|
slot_id: *slot_id,
|
||||||
class: unit.load_class(class.0, avm2, mc)?,
|
class: unit.load_class(class.0, avm2, mc)?,
|
||||||
|
@ -151,8 +241,7 @@ impl<'gc> Trait<'gc> {
|
||||||
},
|
},
|
||||||
AbcTraitKind::Function { slot_id, function } => Trait {
|
AbcTraitKind::Function { slot_id, function } => Trait {
|
||||||
name,
|
name,
|
||||||
is_final: abc_trait.is_final,
|
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||||
is_override: abc_trait.is_override,
|
|
||||||
kind: TraitKind::Function {
|
kind: TraitKind::Function {
|
||||||
slot_id: *slot_id,
|
slot_id: *slot_id,
|
||||||
function: unit.load_method(function.0, mc)?,
|
function: unit.load_method(function.0, mc)?,
|
||||||
|
@ -164,8 +253,7 @@ impl<'gc> Trait<'gc> {
|
||||||
value,
|
value,
|
||||||
} => Trait {
|
} => Trait {
|
||||||
name,
|
name,
|
||||||
is_final: abc_trait.is_final,
|
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||||
is_override: abc_trait.is_override,
|
|
||||||
kind: TraitKind::Const {
|
kind: TraitKind::Const {
|
||||||
slot_id: *slot_id,
|
slot_id: *slot_id,
|
||||||
type_name: if type_name.0 == 0 {
|
type_name: if type_name.0 == 0 {
|
||||||
|
@ -192,10 +280,27 @@ impl<'gc> Trait<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_final(&self) -> bool {
|
pub fn is_final(&self) -> bool {
|
||||||
self.is_final
|
self.attributes.0.contains(TraitAttributes::Final)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_override(&self) -> bool {
|
pub fn is_override(&self) -> bool {
|
||||||
self.is_override
|
self.attributes.0.contains(TraitAttributes::Override)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_attributes(&mut self, attribs: EnumSet<TraitAttributes>) {
|
||||||
|
self.attributes.0 = attribs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the slot or dispatch ID of this trait.
|
||||||
|
pub fn set_slot_id(&mut self, id: u32) {
|
||||||
|
match &mut self.kind {
|
||||||
|
TraitKind::Slot { slot_id, .. } => *slot_id = id,
|
||||||
|
TraitKind::Method { disp_id, .. } => *disp_id = id,
|
||||||
|
TraitKind::Getter { disp_id, .. } => *disp_id = id,
|
||||||
|
TraitKind::Setter { disp_id, .. } => *disp_id = id,
|
||||||
|
TraitKind::Class { slot_id, .. } => *slot_id = id,
|
||||||
|
TraitKind::Function { slot_id, .. } => *slot_id = id,
|
||||||
|
TraitKind::Const { slot_id, .. } => *slot_id = id,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
//! Collect Wrapper Utility
|
||||||
|
|
||||||
|
use gc_arena::Collect;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Collect)]
|
||||||
|
#[collect(require_static)]
|
||||||
|
pub struct CollectWrapper<T>(pub T);
|
|
@ -1,5 +1,6 @@
|
||||||
//! Layout box structure
|
//! Layout box structure
|
||||||
|
|
||||||
|
use crate::collect::CollectWrapper;
|
||||||
use crate::context::UpdateContext;
|
use crate::context::UpdateContext;
|
||||||
use crate::drawing::Drawing;
|
use crate::drawing::Drawing;
|
||||||
use crate::font::{EvalParameters, Font};
|
use crate::font::{EvalParameters, Font};
|
||||||
|
@ -552,10 +553,6 @@ pub struct LayoutBox<'gc> {
|
||||||
content: LayoutContent<'gc>,
|
content: LayoutContent<'gc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Collect)]
|
|
||||||
#[collect(require_static)]
|
|
||||||
pub struct CollectWrapper<T>(T);
|
|
||||||
|
|
||||||
/// Represents different content modes of a given `LayoutBox`.
|
/// Represents different content modes of a given `LayoutBox`.
|
||||||
///
|
///
|
||||||
/// Currently, a `LayoutBox` can contain `Text`, `Bullet`s, or a `Drawing`.
|
/// Currently, a `LayoutBox` can contain `Text`, `Bullet`s, or a `Drawing`.
|
||||||
|
|
|
@ -18,6 +18,7 @@ mod avm1;
|
||||||
mod avm2;
|
mod avm2;
|
||||||
mod bounding_box;
|
mod bounding_box;
|
||||||
mod character;
|
mod character;
|
||||||
|
mod collect;
|
||||||
pub mod color_transform;
|
pub mod color_transform;
|
||||||
mod context;
|
mod context;
|
||||||
mod drawing;
|
mod drawing;
|
||||||
|
|
|
@ -259,6 +259,7 @@ impl Player {
|
||||||
storage,
|
storage,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
player.mutate_with_update_context(|context| Avm2::load_player_globals(context))?;
|
||||||
player.build_matrices();
|
player.build_matrices();
|
||||||
player.audio.set_frame_rate(frame_rate);
|
player.audio.set_frame_rate(frame_rate);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue