diff --git a/core/src/avm1/globals.rs b/core/src/avm1/globals.rs index af6da3e73..0fb8f40c7 100644 --- a/core/src/avm1/globals.rs +++ b/core/src/avm1/globals.rs @@ -15,6 +15,7 @@ pub(crate) mod boolean; pub(crate) mod button; mod color; pub(crate) mod display_object; +pub(crate) mod error; mod function; mod key; mod math; @@ -201,6 +202,9 @@ pub fn create_globals<'gc>( let array_proto: Object<'gc> = array::create_proto(gc_context, object_proto, function_proto); let color_proto: Object<'gc> = color::create_proto(gc_context, object_proto, function_proto); + + let error_proto: Object<'gc> = error::create_proto(gc_context, object_proto, function_proto); + let xmlnode_proto: Object<'gc> = xml::create_xmlnode_proto(gc_context, object_proto, function_proto); @@ -230,6 +234,12 @@ pub fn create_globals<'gc>( Some(function_proto), Some(color_proto), ); + let error = FunctionObject::function( + gc_context, + Executable::Native(error::constructor), + Some(function_proto), + Some(error_proto), + ); let function = FunctionObject::function( gc_context, Executable::Native(function::constructor), @@ -304,6 +314,7 @@ pub fn create_globals<'gc>( globals.define_value(gc_context, "Array", array.into(), EnumSet::empty()); globals.define_value(gc_context, "Button", button.into(), EnumSet::empty()); globals.define_value(gc_context, "Color", color.into(), EnumSet::empty()); + globals.define_value(gc_context, "Error", error.into(), EnumSet::empty()); globals.define_value(gc_context, "Object", object.into(), EnumSet::empty()); globals.define_value(gc_context, "Function", function.into(), EnumSet::empty()); globals.define_value(gc_context, "MovieClip", movie_clip.into(), EnumSet::empty()); diff --git a/core/src/avm1/globals/error.rs b/core/src/avm1/globals/error.rs new file mode 100644 index 000000000..8705b8cf4 --- /dev/null +++ b/core/src/avm1/globals/error.rs @@ -0,0 +1,54 @@ +//! Error object + +use crate::avm1::activation::Activation; +use crate::avm1::error::Error; +use crate::avm1::property::Attribute::*; +use crate::avm1::{Object, ScriptObject, TObject, UpdateContext, Value}; +use enumset::EnumSet; +use gc_arena::MutationContext; + +pub fn constructor<'gc>( + activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let message: Value<'gc> = args.get(0).cloned().unwrap_or(Value::Undefined); + + if message != Value::Undefined { + this.set("message", message, activation, context)?; + } + + Ok(Value::Undefined) +} + +pub fn create_proto<'gc>( + gc_context: MutationContext<'gc, '_>, + proto: Object<'gc>, + fn_proto: Object<'gc>, +) -> Object<'gc> { + let mut object = ScriptObject::object(gc_context, Some(proto)); + + object.define_value(gc_context, "message", "Error".into(), EnumSet::empty()); + object.define_value(gc_context, "name", "Error".into(), EnumSet::empty()); + + object.force_set_function( + "toString", + to_string, + gc_context, + DontDelete | ReadOnly | DontEnum, + Some(fn_proto), + ); + + object.into() +} + +fn to_string<'gc>( + activation: &mut Activation<'_, 'gc>, + context: &mut UpdateContext<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let message = this.get("message", activation, context)?; + Ok(message.coerce_to_string(activation, context)?.into()) +}