avm1: Implement Boolean class
This commit is contained in:
parent
e71099edd5
commit
d9e7a6a960
|
@ -10,6 +10,7 @@ use rand::Rng;
|
|||
use std::f64;
|
||||
|
||||
mod array;
|
||||
pub(crate) mod boolean;
|
||||
mod color;
|
||||
mod function;
|
||||
mod key;
|
||||
|
@ -65,19 +66,6 @@ pub fn random<'gc>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn boolean<'gc>(
|
||||
avm: &mut Avm1<'gc>,
|
||||
_action_context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
_this: Object<'gc>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error> {
|
||||
if let Some(val) = args.get(0) {
|
||||
Ok(val.as_bool(avm.current_swf_version()).into())
|
||||
} else {
|
||||
Ok(false.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_nan<'gc>(
|
||||
avm: &mut Avm1<'gc>,
|
||||
action_context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
|
@ -131,6 +119,7 @@ pub struct SystemPrototypes<'gc> {
|
|||
pub xml_node: Object<'gc>,
|
||||
pub string: Object<'gc>,
|
||||
pub number: Object<'gc>,
|
||||
pub boolean: Object<'gc>,
|
||||
}
|
||||
|
||||
unsafe impl<'gc> gc_arena::Collect for SystemPrototypes<'gc> {
|
||||
|
@ -145,6 +134,7 @@ unsafe impl<'gc> gc_arena::Collect for SystemPrototypes<'gc> {
|
|||
self.xml_node.trace(cc);
|
||||
self.string.trace(cc);
|
||||
self.number.trace(cc);
|
||||
self.boolean.trace(cc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,6 +165,8 @@ pub fn create_globals<'gc>(
|
|||
|
||||
let string_proto: Object<'gc> = string::create_proto(gc_context, object_proto, function_proto);
|
||||
let number_proto: Object<'gc> = number::create_proto(gc_context, object_proto, function_proto);
|
||||
let boolean_proto: Object<'gc> =
|
||||
boolean::create_proto(gc_context, object_proto, function_proto);
|
||||
|
||||
//TODO: These need to be constructors and should also set `.prototype` on each one
|
||||
let object = ScriptObject::function(
|
||||
|
@ -234,6 +226,8 @@ pub fn create_globals<'gc>(
|
|||
);
|
||||
let string = string::create_string_object(gc_context, Some(string_proto), Some(function_proto));
|
||||
let number = number::create_number_object(gc_context, Some(number_proto), Some(function_proto));
|
||||
let boolean =
|
||||
boolean::create_boolean_object(gc_context, Some(boolean_proto), Some(function_proto));
|
||||
|
||||
let listeners = SystemListeners::new(gc_context, Some(array_proto));
|
||||
|
||||
|
@ -249,13 +243,8 @@ pub fn create_globals<'gc>(
|
|||
globals.define_value(gc_context, "XML", xml.into(), EnumSet::empty());
|
||||
globals.define_value(gc_context, "String", string.into(), EnumSet::empty());
|
||||
globals.define_value(gc_context, "Number", number.into(), EnumSet::empty());
|
||||
globals.force_set_function(
|
||||
"Boolean",
|
||||
boolean,
|
||||
gc_context,
|
||||
EnumSet::empty(),
|
||||
Some(function_proto),
|
||||
);
|
||||
globals.define_value(gc_context, "Boolean", boolean.into(), EnumSet::empty());
|
||||
|
||||
globals.define_value(
|
||||
gc_context,
|
||||
"Math",
|
||||
|
@ -352,6 +341,7 @@ pub fn create_globals<'gc>(
|
|||
xml_node: xmlnode_proto,
|
||||
string: string_proto,
|
||||
number: number_proto,
|
||||
boolean: boolean_proto,
|
||||
},
|
||||
globals.into(),
|
||||
listeners,
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
//! `Boolean` class impl
|
||||
|
||||
use crate::avm1::function::Executable;
|
||||
use crate::avm1::return_value::ReturnValue;
|
||||
use crate::avm1::value_object::ValueObject;
|
||||
use crate::avm1::{Avm1, Error, Object, ScriptObject, TObject, Value};
|
||||
use crate::context::UpdateContext;
|
||||
use enumset::EnumSet;
|
||||
use gc_arena::MutationContext;
|
||||
|
||||
/// `Boolean` constructor/function
|
||||
pub fn boolean<'gc>(
|
||||
avm: &mut Avm1<'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error> {
|
||||
let (ret_value, cons_value) = if let Some(val) = args.get(0) {
|
||||
let b = Value::Bool(val.as_bool(avm.current_swf_version()));
|
||||
(b.clone(), b)
|
||||
} else {
|
||||
(Value::Undefined, Value::Bool(false))
|
||||
};
|
||||
|
||||
// If called from a constructor, populate `this`.
|
||||
if let Some(mut vbox) = this.as_value_object() {
|
||||
vbox.replace_value(context.gc_context, cons_value);
|
||||
}
|
||||
|
||||
// If called as a function, return the value.
|
||||
// Boolean() with no argument returns undefined.
|
||||
Ok(ret_value.into())
|
||||
}
|
||||
|
||||
pub fn create_boolean_object<'gc>(
|
||||
gc_context: MutationContext<'gc, '_>,
|
||||
boolean_proto: Option<Object<'gc>>,
|
||||
fn_proto: Option<Object<'gc>>,
|
||||
) -> Object<'gc> {
|
||||
ScriptObject::function(
|
||||
gc_context,
|
||||
Executable::Native(boolean),
|
||||
fn_proto,
|
||||
boolean_proto,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates `Boolean.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
gc_context: MutationContext<'gc, '_>,
|
||||
proto: Object<'gc>,
|
||||
fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
let boolean_proto = ValueObject::empty_box(gc_context, Some(proto));
|
||||
let mut object = boolean_proto.as_script_object().unwrap();
|
||||
|
||||
object.force_set_function(
|
||||
"toString",
|
||||
to_string,
|
||||
gc_context,
|
||||
EnumSet::empty(),
|
||||
Some(fn_proto),
|
||||
);
|
||||
object.force_set_function(
|
||||
"valueOf",
|
||||
value_of,
|
||||
gc_context,
|
||||
EnumSet::empty(),
|
||||
Some(fn_proto),
|
||||
);
|
||||
|
||||
boolean_proto
|
||||
}
|
||||
|
||||
pub fn to_string<'gc>(
|
||||
_avm: &mut Avm1<'gc>,
|
||||
_context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error> {
|
||||
if let Some(vbox) = this.as_value_object() {
|
||||
// Must be a bool.
|
||||
// Boolean.prototype.toString.call(x) returns undefined for non-bools.
|
||||
if let Value::Bool(b) = vbox.unbox() {
|
||||
return Ok(b.to_string().into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Undefined.into())
|
||||
}
|
||||
|
||||
pub fn value_of<'gc>(
|
||||
_avm: &mut Avm1<'gc>,
|
||||
_context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error> {
|
||||
if let Some(vbox) = this.as_value_object() {
|
||||
// Must be a bool.
|
||||
// Boolean.prototype.valueOf.call(x) returns undefined for non-bools.
|
||||
if let Value::Bool(b) = vbox.unbox() {
|
||||
return Ok(b.into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Undefined.into())
|
||||
}
|
|
@ -47,6 +47,7 @@ impl<'gc> ValueObject<'gc> {
|
|||
ob
|
||||
} else {
|
||||
let proto = match &value {
|
||||
Value::Bool(_) => Some(avm.prototypes.boolean),
|
||||
Value::Number(_) => Some(avm.prototypes.number),
|
||||
Value::String(_) => Some(avm.prototypes.string),
|
||||
_ => None,
|
||||
|
@ -62,6 +63,10 @@ impl<'gc> ValueObject<'gc> {
|
|||
|
||||
// Constructor populates the boxed object with the value.
|
||||
match &value {
|
||||
Value::Bool(_) => {
|
||||
let _ =
|
||||
crate::avm1::globals::boolean::boolean(avm, context, obj.into(), &[value]);
|
||||
}
|
||||
Value::Number(_) => {
|
||||
let _ =
|
||||
crate::avm1::globals::number::number(avm, context, obj.into(), &[value]);
|
||||
|
|
Loading…
Reference in New Issue