core: Split construct and call for function objects
This commit is contained in:
parent
337e3292dd
commit
e83dbf7327
|
@ -1799,7 +1799,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.call("[ctor]", self, context, this, None, &args)?;
|
constructor.construct("[ctor]", self, context, this, None, &args)?;
|
||||||
|
|
||||||
self.avm.push(this);
|
self.avm.push(this);
|
||||||
|
|
||||||
|
|
|
@ -419,6 +419,8 @@ pub struct FunctionObject<'gc> {
|
||||||
struct FunctionObjectData<'gc> {
|
struct FunctionObjectData<'gc> {
|
||||||
/// The code that will be invoked when this object is called.
|
/// The code that will be invoked when this object is called.
|
||||||
function: Option<Executable<'gc>>,
|
function: Option<Executable<'gc>>,
|
||||||
|
/// The code that will be invoked when this object is constructed.
|
||||||
|
constructor: Option<Executable<'gc>>,
|
||||||
|
|
||||||
/// The value to be returned by `toString` and `valueOf`.
|
/// The value to be returned by `toString` and `valueOf`.
|
||||||
primitive: Value<'gc>,
|
primitive: Value<'gc>,
|
||||||
|
@ -428,24 +430,29 @@ impl<'gc> FunctionObject<'gc> {
|
||||||
/// Construct a function sans prototype.
|
/// Construct a function sans prototype.
|
||||||
pub fn bare_function(
|
pub fn bare_function(
|
||||||
gc_context: MutationContext<'gc, '_>,
|
gc_context: MutationContext<'gc, '_>,
|
||||||
function: impl Into<Executable<'gc>>,
|
function: Option<impl Into<Executable<'gc>>>,
|
||||||
|
constructor: Option<impl Into<Executable<'gc>>>,
|
||||||
fn_proto: Option<Object<'gc>>,
|
fn_proto: Option<Object<'gc>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let base = ScriptObject::object(gc_context, fn_proto);
|
let base = ScriptObject::object(gc_context, fn_proto);
|
||||||
|
|
||||||
|
let func = function.map(|x| x.into());
|
||||||
|
let cons = constructor.map(|x| x.into());
|
||||||
|
|
||||||
FunctionObject {
|
FunctionObject {
|
||||||
base,
|
base,
|
||||||
data: GcCell::allocate(
|
data: GcCell::allocate(
|
||||||
gc_context,
|
gc_context,
|
||||||
FunctionObjectData {
|
FunctionObjectData {
|
||||||
function: Some(function.into()),
|
function: func,
|
||||||
primitive: "[type Function]".into(),
|
primitive: "[type Function]".into(),
|
||||||
|
constructor: cons,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a function from an executable and associated protos.
|
/// Construct a function with any combination of regular and constructor parts.
|
||||||
///
|
///
|
||||||
/// Since prototypes need to link back to themselves, this function builds
|
/// Since prototypes need to link back to themselves, this function builds
|
||||||
/// both objects itself and returns the function to you, fully allocated.
|
/// both objects itself and returns the function to you, fully allocated.
|
||||||
|
@ -453,13 +460,14 @@ impl<'gc> FunctionObject<'gc> {
|
||||||
/// `fn_proto` refers to the implicit proto of the function object, and the
|
/// `fn_proto` refers to the implicit proto of the function object, and the
|
||||||
/// `prototype` refers to the explicit prototype of the function. If
|
/// `prototype` refers to the explicit prototype of the function. If
|
||||||
/// provided, the function and it's prototype will be linked to each other.
|
/// provided, the function and it's prototype will be linked to each other.
|
||||||
pub fn function(
|
fn allocate_function(
|
||||||
context: MutationContext<'gc, '_>,
|
context: MutationContext<'gc, '_>,
|
||||||
function: impl Into<Executable<'gc>>,
|
function: Option<impl Into<Executable<'gc>>>,
|
||||||
|
constructor: Option<impl Into<Executable<'gc>>>,
|
||||||
fn_proto: Option<Object<'gc>>,
|
fn_proto: Option<Object<'gc>>,
|
||||||
prototype: Option<Object<'gc>>,
|
prototype: Option<Object<'gc>>,
|
||||||
) -> Object<'gc> {
|
) -> Object<'gc> {
|
||||||
let function = Self::bare_function(context, function, fn_proto).into();
|
let function = Self::bare_function(context, function, constructor, fn_proto).into();
|
||||||
|
|
||||||
if let Some(p) = prototype {
|
if let Some(p) = prototype {
|
||||||
p.define_value(
|
p.define_value(
|
||||||
|
@ -473,6 +481,47 @@ impl<'gc> FunctionObject<'gc> {
|
||||||
|
|
||||||
function
|
function
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Construct a regular function from an executable and associated protos.
|
||||||
|
pub fn function(
|
||||||
|
context: MutationContext<'gc, '_>,
|
||||||
|
function: impl Into<Executable<'gc>>,
|
||||||
|
fn_proto: Option<Object<'gc>>,
|
||||||
|
prototype: Option<Object<'gc>>,
|
||||||
|
) -> Object<'gc> {
|
||||||
|
// Avoid type inference issues
|
||||||
|
let none: Option<Executable> = None;
|
||||||
|
Self::allocate_function(context, Some(function), none, fn_proto, prototype)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a constructor function from an executable and associated protos.
|
||||||
|
pub fn constructor(
|
||||||
|
context: MutationContext<'gc, '_>,
|
||||||
|
constructor: impl Into<Executable<'gc>>,
|
||||||
|
fn_proto: Option<Object<'gc>>,
|
||||||
|
prototype: Option<Object<'gc>>,
|
||||||
|
) -> Object<'gc> {
|
||||||
|
// Avoid type inference issues
|
||||||
|
let none: Option<Executable> = None;
|
||||||
|
Self::allocate_function(context, none, Some(constructor), fn_proto, prototype)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a regular and constructor function from an executable and associated protos.
|
||||||
|
pub fn function_and_constructor(
|
||||||
|
context: MutationContext<'gc, '_>,
|
||||||
|
function: impl Into<Executable<'gc>>,
|
||||||
|
constructor: impl Into<Executable<'gc>>,
|
||||||
|
fn_proto: Option<Object<'gc>>,
|
||||||
|
prototype: Option<Object<'gc>>,
|
||||||
|
) -> Object<'gc> {
|
||||||
|
Self::allocate_function(
|
||||||
|
context,
|
||||||
|
Some(function),
|
||||||
|
Some(constructor),
|
||||||
|
fn_proto,
|
||||||
|
prototype,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
||||||
|
@ -521,6 +570,32 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn construct(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
activation: &mut Activation<'_, 'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
this: Object<'gc>,
|
||||||
|
base_proto: Option<Object<'gc>>,
|
||||||
|
args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
|
println!("Constructing a function {}: {:?}", name, &self.data.read());
|
||||||
|
if let Some(exec) = &self.data.read().constructor {
|
||||||
|
exec.exec(
|
||||||
|
name,
|
||||||
|
activation,
|
||||||
|
context,
|
||||||
|
this,
|
||||||
|
base_proto,
|
||||||
|
args,
|
||||||
|
ExecutionReason::FunctionCall,
|
||||||
|
(*self).into(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.call(name, activation, context, this, base_proto, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn call_setter(
|
fn call_setter(
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
@ -547,6 +622,7 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
||||||
FunctionObjectData {
|
FunctionObjectData {
|
||||||
function: None,
|
function: None,
|
||||||
primitive: "[type Function]".into(),
|
primitive: "[type Function]".into(),
|
||||||
|
constructor: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
|
@ -282,74 +282,74 @@ pub fn create_globals<'gc>(
|
||||||
let context_menu_item_proto =
|
let context_menu_item_proto =
|
||||||
context_menu_item::create_proto(gc_context, object_proto, function_proto);
|
context_menu_item::create_proto(gc_context, object_proto, function_proto);
|
||||||
|
|
||||||
let button = FunctionObject::function(
|
let button = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(button::constructor),
|
Executable::Native(button::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
Some(button_proto),
|
Some(button_proto),
|
||||||
);
|
);
|
||||||
let color = FunctionObject::function(
|
let color = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(color::constructor),
|
Executable::Native(color::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
Some(color_proto),
|
Some(color_proto),
|
||||||
);
|
);
|
||||||
let error = FunctionObject::function(
|
let error = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(error::constructor),
|
Executable::Native(error::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
Some(error_proto),
|
Some(error_proto),
|
||||||
);
|
);
|
||||||
let function = FunctionObject::function(
|
let function = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(function::constructor),
|
Executable::Native(function::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
);
|
);
|
||||||
let load_vars = FunctionObject::function(
|
let load_vars = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(load_vars::constructor),
|
Executable::Native(load_vars::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
Some(load_vars_proto),
|
Some(load_vars_proto),
|
||||||
);
|
);
|
||||||
let movie_clip = FunctionObject::function(
|
let movie_clip = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(movie_clip::constructor),
|
Executable::Native(movie_clip::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
Some(movie_clip_proto),
|
Some(movie_clip_proto),
|
||||||
);
|
);
|
||||||
let movie_clip_loader = FunctionObject::function(
|
let movie_clip_loader = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(movie_clip_loader::constructor),
|
Executable::Native(movie_clip_loader::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
Some(movie_clip_loader_proto),
|
Some(movie_clip_loader_proto),
|
||||||
);
|
);
|
||||||
let sound = FunctionObject::function(
|
let sound = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(sound::constructor),
|
Executable::Native(sound::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
Some(sound_proto),
|
Some(sound_proto),
|
||||||
);
|
);
|
||||||
let text_field = FunctionObject::function(
|
let text_field = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(text_field::constructor),
|
Executable::Native(text_field::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
Some(text_field_proto),
|
Some(text_field_proto),
|
||||||
);
|
);
|
||||||
let text_format = FunctionObject::function(
|
let text_format = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(text_format::constructor),
|
Executable::Native(text_format::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
Some(text_format_proto),
|
Some(text_format_proto),
|
||||||
);
|
);
|
||||||
let array = array::create_array_object(gc_context, Some(array_proto), Some(function_proto));
|
let array = array::create_array_object(gc_context, Some(array_proto), Some(function_proto));
|
||||||
let xmlnode = FunctionObject::function(
|
let xmlnode = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(xml::xmlnode_constructor),
|
Executable::Native(xml::xmlnode_constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
Some(xmlnode_proto),
|
Some(xmlnode_proto),
|
||||||
);
|
);
|
||||||
let xml = FunctionObject::function(
|
let xml = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(xml::xml_constructor),
|
Executable::Native(xml::xml_constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
|
@ -434,7 +434,7 @@ pub fn create_globals<'gc>(
|
||||||
globals.define_value(
|
globals.define_value(
|
||||||
gc_context,
|
gc_context,
|
||||||
"ContextMenu",
|
"ContextMenu",
|
||||||
FunctionObject::function(
|
FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(context_menu::constructor),
|
Executable::Native(context_menu::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
|
@ -447,7 +447,7 @@ pub fn create_globals<'gc>(
|
||||||
globals.define_value(
|
globals.define_value(
|
||||||
gc_context,
|
gc_context,
|
||||||
"ContextMenuItem",
|
"ContextMenuItem",
|
||||||
FunctionObject::function(
|
FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(context_menu_item::constructor),
|
Executable::Native(context_menu_item::constructor),
|
||||||
Some(function_proto),
|
Some(function_proto),
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub fn create_array_object<'gc>(
|
||||||
array_proto: Option<Object<'gc>>,
|
array_proto: Option<Object<'gc>>,
|
||||||
fn_proto: Option<Object<'gc>>,
|
fn_proto: Option<Object<'gc>>,
|
||||||
) -> Object<'gc> {
|
) -> Object<'gc> {
|
||||||
let array = FunctionObject::function(
|
let array = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(constructor),
|
Executable::Native(constructor),
|
||||||
fn_proto,
|
fn_proto,
|
||||||
|
@ -87,7 +87,7 @@ pub fn create_array_object<'gc>(
|
||||||
array
|
array
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements `Array`
|
/// Implements `Array` constructor
|
||||||
pub fn constructor<'gc>(
|
pub fn constructor<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
|
|
@ -9,25 +9,40 @@ use crate::context::UpdateContext;
|
||||||
use enumset::EnumSet;
|
use enumset::EnumSet;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::MutationContext;
|
||||||
|
|
||||||
/// `Boolean` constructor/function
|
/// `Boolean` constructor
|
||||||
pub fn boolean<'gc>(
|
pub fn constructor<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
this: Object<'gc>,
|
this: Object<'gc>,
|
||||||
args: &[Value<'gc>],
|
args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
let (ret_value, cons_value) = if let Some(val) = args.get(0) {
|
let cons_value = if let Some(val) = args.get(0) {
|
||||||
let b = Value::Bool(val.as_bool(activation.current_swf_version()));
|
Value::Bool(val.as_bool(activation.current_swf_version()))
|
||||||
(b.clone(), b)
|
|
||||||
} else {
|
} else {
|
||||||
(Value::Undefined, Value::Bool(false))
|
Value::Bool(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
// If called from a constructor, populate `this`.
|
// Called from a constructor, populate `this`.
|
||||||
if let Some(mut vbox) = this.as_value_object() {
|
if let Some(mut vbox) = this.as_value_object() {
|
||||||
vbox.replace_value(context.gc_context, cons_value);
|
vbox.replace_value(context.gc_context, cons_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `Boolean` function
|
||||||
|
pub fn boolean_function<'gc>(
|
||||||
|
activation: &mut Activation<'_, 'gc>,
|
||||||
|
_context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
_this: Object<'gc>,
|
||||||
|
args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
|
let ret_value = if let Some(val) = args.get(0) {
|
||||||
|
Value::Bool(val.as_bool(activation.current_swf_version()))
|
||||||
|
} else {
|
||||||
|
Value::Undefined
|
||||||
|
};
|
||||||
|
|
||||||
// If called as a function, return the value.
|
// If called as a function, return the value.
|
||||||
// Boolean() with no argument returns undefined.
|
// Boolean() with no argument returns undefined.
|
||||||
Ok(ret_value)
|
Ok(ret_value)
|
||||||
|
@ -38,9 +53,10 @@ pub fn create_boolean_object<'gc>(
|
||||||
boolean_proto: Option<Object<'gc>>,
|
boolean_proto: Option<Object<'gc>>,
|
||||||
fn_proto: Option<Object<'gc>>,
|
fn_proto: Option<Object<'gc>>,
|
||||||
) -> Object<'gc> {
|
) -> Object<'gc> {
|
||||||
FunctionObject::function(
|
FunctionObject::function_and_constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(boolean),
|
Executable::Native(boolean_function),
|
||||||
|
Executable::Native(constructor),
|
||||||
fn_proto,
|
fn_proto,
|
||||||
boolean_proto,
|
boolean_proto,
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::context::UpdateContext;
|
||||||
use enumset::EnumSet;
|
use enumset::EnumSet;
|
||||||
use gc_arena::MutationContext;
|
use gc_arena::MutationContext;
|
||||||
|
|
||||||
/// `Number` constructor/function
|
/// `Number` constructor
|
||||||
pub fn number<'gc>(
|
pub fn number<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
@ -28,6 +28,22 @@ pub fn number<'gc>(
|
||||||
vbox.replace_value(context.gc_context, value.into());
|
vbox.replace_value(context.gc_context, value.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `Number` function
|
||||||
|
pub fn number_function<'gc>(
|
||||||
|
activation: &mut Activation<'_, 'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
_this: Object<'gc>,
|
||||||
|
args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
|
let value = if let Some(val) = args.get(0) {
|
||||||
|
val.coerce_to_f64(activation, context)?
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
|
||||||
// If Number is called as a function, return the value.
|
// If Number is called as a function, return the value.
|
||||||
Ok(value.into())
|
Ok(value.into())
|
||||||
}
|
}
|
||||||
|
@ -37,8 +53,9 @@ pub fn create_number_object<'gc>(
|
||||||
number_proto: Option<Object<'gc>>,
|
number_proto: Option<Object<'gc>>,
|
||||||
fn_proto: Option<Object<'gc>>,
|
fn_proto: Option<Object<'gc>>,
|
||||||
) -> Object<'gc> {
|
) -> Object<'gc> {
|
||||||
let number = FunctionObject::function(
|
let number = FunctionObject::function_and_constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
|
Executable::Native(number_function),
|
||||||
Executable::Native(number),
|
Executable::Native(number),
|
||||||
fn_proto,
|
fn_proto,
|
||||||
number_proto,
|
number_proto,
|
||||||
|
|
|
@ -372,7 +372,7 @@ pub fn create_object_object<'gc>(
|
||||||
proto: Object<'gc>,
|
proto: Object<'gc>,
|
||||||
fn_proto: Object<'gc>,
|
fn_proto: Object<'gc>,
|
||||||
) -> Object<'gc> {
|
) -> Object<'gc> {
|
||||||
let object_function = FunctionObject::function(
|
let object_function = FunctionObject::constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
Executable::Native(constructor),
|
Executable::Native(constructor),
|
||||||
Some(fn_proto),
|
Some(fn_proto),
|
||||||
|
|
|
@ -30,6 +30,22 @@ pub fn string<'gc>(
|
||||||
vbox.replace_value(ac.gc_context, value.clone().into());
|
vbox.replace_value(ac.gc_context, value.clone().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `String` function
|
||||||
|
pub fn string_function<'gc>(
|
||||||
|
activation: &mut Activation<'_, 'gc>,
|
||||||
|
ac: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
_this: Object<'gc>,
|
||||||
|
args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
|
let value = match args.get(0).cloned() {
|
||||||
|
Some(Value::String(s)) => s,
|
||||||
|
Some(v) => v.coerce_to_string(activation, ac)?,
|
||||||
|
_ => AvmString::new(ac.gc_context, String::new()),
|
||||||
|
};
|
||||||
|
|
||||||
Ok(value.into())
|
Ok(value.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +54,9 @@ pub fn create_string_object<'gc>(
|
||||||
string_proto: Option<Object<'gc>>,
|
string_proto: Option<Object<'gc>>,
|
||||||
fn_proto: Option<Object<'gc>>,
|
fn_proto: Option<Object<'gc>>,
|
||||||
) -> Object<'gc> {
|
) -> Object<'gc> {
|
||||||
let string = FunctionObject::function(
|
let string = FunctionObject::function_and_constructor(
|
||||||
gc_context,
|
gc_context,
|
||||||
|
Executable::Native(string_function),
|
||||||
Executable::Native(string),
|
Executable::Native(string),
|
||||||
fn_proto,
|
fn_proto,
|
||||||
string_proto,
|
string_proto,
|
||||||
|
|
|
@ -108,6 +108,19 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
args: &[Value<'gc>],
|
args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>>;
|
) -> Result<Value<'gc>, Error<'gc>>;
|
||||||
|
|
||||||
|
/// Construct the underlying object.
|
||||||
|
fn construct(
|
||||||
|
&self,
|
||||||
|
_name: &str,
|
||||||
|
_activation: &mut Activation<'_, 'gc>,
|
||||||
|
_context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
_this: Object<'gc>,
|
||||||
|
_base_proto: Option<Object<'gc>>,
|
||||||
|
_args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
||||||
/// Call a method on the object.
|
/// Call a method on the object.
|
||||||
///
|
///
|
||||||
/// It is highly recommended to use this convenience method to perform
|
/// It is highly recommended to use this convenience method to perform
|
||||||
|
|
|
@ -62,7 +62,7 @@ impl<'gc> ValueObject<'gc> {
|
||||||
// Constructor populates the boxed object with the value.
|
// Constructor populates the boxed object with the value.
|
||||||
match &value {
|
match &value {
|
||||||
Value::Bool(_) => {
|
Value::Bool(_) => {
|
||||||
let _ = crate::avm1::globals::boolean::boolean(
|
let _ = crate::avm1::globals::boolean::constructor(
|
||||||
activation,
|
activation,
|
||||||
context,
|
context,
|
||||||
obj.into(),
|
obj.into(),
|
||||||
|
|
Loading…
Reference in New Issue