avm1: Implement Boolean class
This commit is contained in:
parent
e71099edd5
commit
d9e7a6a960
|
@ -10,6 +10,7 @@ use rand::Rng;
|
||||||
use std::f64;
|
use std::f64;
|
||||||
|
|
||||||
mod array;
|
mod array;
|
||||||
|
pub(crate) mod boolean;
|
||||||
mod color;
|
mod color;
|
||||||
mod function;
|
mod function;
|
||||||
mod key;
|
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>(
|
pub fn is_nan<'gc>(
|
||||||
avm: &mut Avm1<'gc>,
|
avm: &mut Avm1<'gc>,
|
||||||
action_context: &mut UpdateContext<'_, 'gc, '_>,
|
action_context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
@ -131,6 +119,7 @@ pub struct SystemPrototypes<'gc> {
|
||||||
pub xml_node: Object<'gc>,
|
pub xml_node: Object<'gc>,
|
||||||
pub string: Object<'gc>,
|
pub string: Object<'gc>,
|
||||||
pub number: Object<'gc>,
|
pub number: Object<'gc>,
|
||||||
|
pub boolean: Object<'gc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'gc> gc_arena::Collect for SystemPrototypes<'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.xml_node.trace(cc);
|
||||||
self.string.trace(cc);
|
self.string.trace(cc);
|
||||||
self.number.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 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 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
|
//TODO: These need to be constructors and should also set `.prototype` on each one
|
||||||
let object = ScriptObject::function(
|
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 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 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));
|
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, "XML", xml.into(), EnumSet::empty());
|
||||||
globals.define_value(gc_context, "String", string.into(), EnumSet::empty());
|
globals.define_value(gc_context, "String", string.into(), EnumSet::empty());
|
||||||
globals.define_value(gc_context, "Number", number.into(), EnumSet::empty());
|
globals.define_value(gc_context, "Number", number.into(), EnumSet::empty());
|
||||||
globals.force_set_function(
|
globals.define_value(gc_context, "Boolean", boolean.into(), EnumSet::empty());
|
||||||
"Boolean",
|
|
||||||
boolean,
|
|
||||||
gc_context,
|
|
||||||
EnumSet::empty(),
|
|
||||||
Some(function_proto),
|
|
||||||
);
|
|
||||||
globals.define_value(
|
globals.define_value(
|
||||||
gc_context,
|
gc_context,
|
||||||
"Math",
|
"Math",
|
||||||
|
@ -352,6 +341,7 @@ pub fn create_globals<'gc>(
|
||||||
xml_node: xmlnode_proto,
|
xml_node: xmlnode_proto,
|
||||||
string: string_proto,
|
string: string_proto,
|
||||||
number: number_proto,
|
number: number_proto,
|
||||||
|
boolean: boolean_proto,
|
||||||
},
|
},
|
||||||
globals.into(),
|
globals.into(),
|
||||||
listeners,
|
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
|
ob
|
||||||
} else {
|
} else {
|
||||||
let proto = match &value {
|
let proto = match &value {
|
||||||
|
Value::Bool(_) => Some(avm.prototypes.boolean),
|
||||||
Value::Number(_) => Some(avm.prototypes.number),
|
Value::Number(_) => Some(avm.prototypes.number),
|
||||||
Value::String(_) => Some(avm.prototypes.string),
|
Value::String(_) => Some(avm.prototypes.string),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -62,6 +63,10 @@ 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(_) => {
|
||||||
|
let _ =
|
||||||
|
crate::avm1::globals::boolean::boolean(avm, context, obj.into(), &[value]);
|
||||||
|
}
|
||||||
Value::Number(_) => {
|
Value::Number(_) => {
|
||||||
let _ =
|
let _ =
|
||||||
crate::avm1::globals::number::number(avm, context, obj.into(), &[value]);
|
crate::avm1::globals::number::number(avm, context, obj.into(), &[value]);
|
||||||
|
|
Loading…
Reference in New Issue