avm2: Make numbers appear to be of any numeric type that can represent them.
This also prevents an exception from being fired when testing `undefined` or `null`, which are valid inputs to `istype`.
This commit is contained in:
parent
974fe152ff
commit
e38b1bc281
|
@ -2381,7 +2381,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
method: Gc<'gc, BytecodeMethod<'gc>>,
|
method: Gc<'gc, BytecodeMethod<'gc>>,
|
||||||
type_name_index: Index<AbcMultiname>,
|
type_name_index: Index<AbcMultiname>,
|
||||||
) -> Result<FrameControl<'gc>, Error> {
|
) -> Result<FrameControl<'gc>, Error> {
|
||||||
let value = self.context.avm2.pop().coerce_to_object(self)?;
|
let value = self.context.avm2.pop();
|
||||||
|
|
||||||
let multiname = self.pool_multiname_static(method, type_name_index)?;
|
let multiname = self.pool_multiname_static(method, type_name_index)?;
|
||||||
let found: Result<Value<'gc>, Error> = if let Some(scope) = self.scope() {
|
let found: Result<Value<'gc>, Error> = if let Some(scope) = self.scope() {
|
||||||
|
@ -2400,7 +2400,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
});
|
});
|
||||||
let type_object = found?.coerce_to_object(self)?;
|
let type_object = found?.coerce_to_object(self)?;
|
||||||
|
|
||||||
let is_instance_of = value.is_of_type(type_object)?;
|
let is_instance_of = value.is_of_type(self, type_object)?;
|
||||||
self.context.avm2.push(is_instance_of);
|
self.context.avm2.push(is_instance_of);
|
||||||
|
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
|
@ -2408,9 +2408,9 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
|
|
||||||
fn op_is_type_late(&mut self) -> Result<FrameControl<'gc>, Error> {
|
fn op_is_type_late(&mut self) -> Result<FrameControl<'gc>, Error> {
|
||||||
let type_object = self.context.avm2.pop().coerce_to_object(self)?;
|
let type_object = self.context.avm2.pop().coerce_to_object(self)?;
|
||||||
let value = self.context.avm2.pop().coerce_to_object(self)?;
|
let value = self.context.avm2.pop();
|
||||||
|
|
||||||
let is_instance_of = value.is_of_type(type_object)?;
|
let is_instance_of = value.is_of_type(self, type_object)?;
|
||||||
|
|
||||||
self.context.avm2.push(is_instance_of);
|
self.context.avm2.push(is_instance_of);
|
||||||
|
|
||||||
|
|
|
@ -1059,6 +1059,15 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unwrap this object as an immutable primitive value.
|
||||||
|
///
|
||||||
|
/// This function should not be called in cases where a normal `Value`
|
||||||
|
/// coercion would do. It *only* accounts for boxed primitives, and not
|
||||||
|
/// `valueOf`.
|
||||||
|
fn as_primitive(&self) -> Option<Ref<Value<'gc>>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Unwrap this object as a mutable primitive value.
|
/// Unwrap this object as a mutable primitive value.
|
||||||
fn as_primitive_mut(&self, _mc: MutationContext<'gc, '_>) -> Option<RefMut<Value<'gc>>> {
|
fn as_primitive_mut(&self, _mc: MutationContext<'gc, '_>) -> Option<RefMut<Value<'gc>>> {
|
||||||
None
|
None
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Boxed primitives
|
//! Boxed primitives
|
||||||
|
|
||||||
use std::cell::RefMut;
|
use std::cell::{Ref, RefMut};
|
||||||
|
|
||||||
use crate::avm2::activation::Activation;
|
use crate::avm2::activation::Activation;
|
||||||
use crate::avm2::class::Class;
|
use crate::avm2::class::Class;
|
||||||
|
@ -141,4 +141,8 @@ impl<'gc> TObject<'gc> for PrimitiveObject<'gc> {
|
||||||
fn as_primitive_mut(&self, mc: MutationContext<'gc, '_>) -> Option<RefMut<Value<'gc>>> {
|
fn as_primitive_mut(&self, mc: MutationContext<'gc, '_>) -> Option<RefMut<Value<'gc>>> {
|
||||||
Some(RefMut::map(self.0.write(mc), |pod| &mut pod.primitive))
|
Some(RefMut::map(self.0.write(mc), |pod| &mut pod.primitive))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_primitive(&self) -> Option<Ref<Value<'gc>>> {
|
||||||
|
Some(Ref::map(self.0.read(), |pod| &pod.primitive))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -631,6 +631,75 @@ impl<'gc> Value<'gc> {
|
||||||
Ok(self.clone())
|
Ok(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determine if this value is any kind of number.
|
||||||
|
pub fn is_number(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Value::Number(_) => true,
|
||||||
|
Value::Integer(_) => true,
|
||||||
|
Value::Unsigned(_) => true,
|
||||||
|
Value::Object(o) => o.as_primitive().map(|p| p.is_number()).unwrap_or(false),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determine if this value is a number representable as a u32 without loss
|
||||||
|
/// of precision.
|
||||||
|
#[allow(clippy::float_cmp)]
|
||||||
|
pub fn is_u32(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Value::Number(n) => *n == n.round() && n.is_sign_positive() && *n <= u32::MAX as f64,
|
||||||
|
Value::Integer(i) => i.is_positive() || *i == 0,
|
||||||
|
Value::Unsigned(_) => true,
|
||||||
|
Value::Object(o) => o.as_primitive().map(|p| p.is_u32()).unwrap_or(false),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determine if this value is a number representable as an i32 without
|
||||||
|
/// loss of precision.
|
||||||
|
#[allow(clippy::float_cmp)]
|
||||||
|
pub fn is_i32(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Value::Number(n) => *n == n.round() && *n >= i32::MIN as f64 && *n <= i32::MAX as f64,
|
||||||
|
Value::Integer(_) => true,
|
||||||
|
Value::Unsigned(u) => *u <= i32::MAX as u32,
|
||||||
|
Value::Object(o) => o.as_primitive().map(|p| p.is_u32()).unwrap_or(false),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determine if this value is of a given type.
|
||||||
|
///
|
||||||
|
/// This implements a particularly unusual rule: primitive numeric values
|
||||||
|
/// considered instances of all numeric types that can represent them. For
|
||||||
|
/// example, 5 is simultaneously an instance of `int`, `uint`, and
|
||||||
|
/// `Number`.
|
||||||
|
pub fn is_of_type(
|
||||||
|
&self,
|
||||||
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
type_object: Object<'gc>,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
|
if let Some(type_class) = type_object.as_class() {
|
||||||
|
if type_class.read().name() == &QName::new(Namespace::public(), "Number") {
|
||||||
|
return Ok(self.is_number());
|
||||||
|
}
|
||||||
|
|
||||||
|
if type_class.read().name() == &QName::new(Namespace::public(), "uint") {
|
||||||
|
return Ok(self.is_u32());
|
||||||
|
}
|
||||||
|
|
||||||
|
if type_class.read().name() == &QName::new(Namespace::public(), "int") {
|
||||||
|
return Ok(self.is_i32());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(o) = self.coerce_to_object(activation) {
|
||||||
|
o.is_of_type(type_object)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Determine if two values are abstractly equal to each other.
|
/// Determine if two values are abstractly equal to each other.
|
||||||
///
|
///
|
||||||
/// This abstract equality algorithm is intended to match ECMA-262 3rd
|
/// This abstract equality algorithm is intended to match ECMA-262 3rd
|
||||||
|
|
|
@ -0,0 +1,232 @@
|
||||||
|
package {
|
||||||
|
public class Test {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CoercibleAsIntString {
|
||||||
|
public function toString() {
|
||||||
|
return "-99.13";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CoercibleAsNonIntString {
|
||||||
|
public function toString() {
|
||||||
|
return "TEST FAIL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CoercibleAsValue {
|
||||||
|
public function valueOf() {
|
||||||
|
return 23.16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotCoercibleAsValue {
|
||||||
|
public function valueOf() {
|
||||||
|
return "TEST FAIL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace("// == int tests == ");
|
||||||
|
trace("//undefined is int");
|
||||||
|
trace(undefined is int);
|
||||||
|
trace("//null is int");
|
||||||
|
trace(null is int);
|
||||||
|
trace("//true is int");
|
||||||
|
trace(true is int);
|
||||||
|
trace("//false is int");
|
||||||
|
trace(false is int);
|
||||||
|
trace("//0 is int");
|
||||||
|
trace(0 is int);
|
||||||
|
trace("//1 is int");
|
||||||
|
trace(1 is int);
|
||||||
|
trace("//5.12 is int");
|
||||||
|
trace(5.12 is int);
|
||||||
|
trace("//(5.12 - .12) is int");
|
||||||
|
trace((5.12 - .12) is int);
|
||||||
|
trace("//-6 is int");
|
||||||
|
trace(-6 is int);
|
||||||
|
trace("//\"12.23\" is int");
|
||||||
|
trace("12.23" is int);
|
||||||
|
trace("//\"true\" is int");
|
||||||
|
trace("true" is int);
|
||||||
|
trace("//\"false\" is int");
|
||||||
|
trace("false" is int);
|
||||||
|
trace("//new CoercibleAsIntString() is int");
|
||||||
|
trace(new CoercibleAsIntString() is int);
|
||||||
|
trace("//new CoercibleAsNonIntString() is int");
|
||||||
|
trace(new CoercibleAsNonIntString() is int);
|
||||||
|
trace("//new CoercibleAsValue() is int");
|
||||||
|
trace(new CoercibleAsValue() is int);
|
||||||
|
trace("//new NotCoercibleAsValue() is int");
|
||||||
|
trace(new NotCoercibleAsValue() is int);
|
||||||
|
|
||||||
|
trace("// == uint tests == ");
|
||||||
|
trace("//undefined is uint");
|
||||||
|
trace(undefined is uint);
|
||||||
|
trace("//null is uint");
|
||||||
|
trace(null is uint);
|
||||||
|
trace("//true is uint");
|
||||||
|
trace(true is uint);
|
||||||
|
trace("//false is uint");
|
||||||
|
trace(false is uint);
|
||||||
|
trace("//0 is uint");
|
||||||
|
trace(0 is uint);
|
||||||
|
trace("//1 is uint");
|
||||||
|
trace(1 is uint);
|
||||||
|
trace("//5.12 is uint");
|
||||||
|
trace(5.12 is uint);
|
||||||
|
trace("//(5.12 - .12) is uint");
|
||||||
|
trace((5.12 - .12) is uint);
|
||||||
|
trace("//-6 is uint");
|
||||||
|
trace(-6 is uint);
|
||||||
|
trace("//\"12.23\" is uint");
|
||||||
|
trace("12.23" is uint);
|
||||||
|
trace("//\"true\" is uint");
|
||||||
|
trace("true" is uint);
|
||||||
|
trace("//\"false\" is uint");
|
||||||
|
trace("false" is uint);
|
||||||
|
trace("//new CoercibleAsIntString() is uint");
|
||||||
|
trace(new CoercibleAsIntString() is uint);
|
||||||
|
trace("//new CoercibleAsNonIntString() is uint");
|
||||||
|
trace(new CoercibleAsNonIntString() is uint);
|
||||||
|
trace("//new CoercibleAsValue() is uint");
|
||||||
|
trace(new CoercibleAsValue() is uint);
|
||||||
|
trace("//new NotCoercibleAsValue() is uint");
|
||||||
|
trace(new NotCoercibleAsValue() is uint);
|
||||||
|
|
||||||
|
trace("// == Number tests == ");
|
||||||
|
trace("//undefined is Number");
|
||||||
|
trace(undefined is Number);
|
||||||
|
trace("//null is Number");
|
||||||
|
trace(null is Number);
|
||||||
|
trace("//true is Number");
|
||||||
|
trace(true is Number);
|
||||||
|
trace("//false is Number");
|
||||||
|
trace(false is Number);
|
||||||
|
trace("//0 is Number");
|
||||||
|
trace(0 is Number);
|
||||||
|
trace("//1 is Number");
|
||||||
|
trace(1 is Number);
|
||||||
|
trace("//5.12 is Number");
|
||||||
|
trace(5.12 is Number);
|
||||||
|
trace("//(5.12 - .12) is Number");
|
||||||
|
trace((5.12 - .12) is Number);
|
||||||
|
trace("//-6 is Number");
|
||||||
|
trace(-6 is Number);
|
||||||
|
trace("//\"12.23\" is Number");
|
||||||
|
trace("12.23" is Number);
|
||||||
|
trace("//\"true\" is Number");
|
||||||
|
trace("true" is Number);
|
||||||
|
trace("//\"false\" is Number");
|
||||||
|
trace("false" is Number);
|
||||||
|
trace("//new CoercibleAsIntString() is Number");
|
||||||
|
trace(new CoercibleAsIntString() is Number);
|
||||||
|
trace("//new CoercibleAsNonIntString() is Number");
|
||||||
|
trace(new CoercibleAsNonIntString() is Number);
|
||||||
|
trace("//new CoercibleAsValue() is Number");
|
||||||
|
trace(new CoercibleAsValue() is Number);
|
||||||
|
trace("//new NotCoercibleAsValue() is Number");
|
||||||
|
trace(new NotCoercibleAsValue() is Number);
|
||||||
|
|
||||||
|
trace("// == Boolean tests == ");
|
||||||
|
trace("//undefined is Boolean");
|
||||||
|
trace(undefined is Boolean);
|
||||||
|
trace("//null is Boolean");
|
||||||
|
trace(null is Boolean);
|
||||||
|
trace("//true is Boolean");
|
||||||
|
trace(true is Boolean);
|
||||||
|
trace("//false is Boolean");
|
||||||
|
trace(false is Boolean);
|
||||||
|
trace("//0 is Boolean");
|
||||||
|
trace(0 is Boolean);
|
||||||
|
trace("//1 is Boolean");
|
||||||
|
trace(1 is Boolean);
|
||||||
|
trace("//5.12 is Boolean");
|
||||||
|
trace(5.12 is Boolean);
|
||||||
|
trace("//(5.12 - .12) is Boolean");
|
||||||
|
trace((5.12 - .12) is Boolean);
|
||||||
|
trace("//-6 is Boolean");
|
||||||
|
trace(-6 is Boolean);
|
||||||
|
trace("//\"12.23\" is Boolean");
|
||||||
|
trace("12.23" is Boolean);
|
||||||
|
trace("//\"true\" is Boolean");
|
||||||
|
trace("true" is Boolean);
|
||||||
|
trace("//\"false\" is Boolean");
|
||||||
|
trace("false" is Boolean);
|
||||||
|
trace("//new CoercibleAsIntString() is Boolean");
|
||||||
|
trace(new CoercibleAsIntString() is Boolean);
|
||||||
|
trace("//new CoercibleAsNonIntString() is Boolean");
|
||||||
|
trace(new CoercibleAsNonIntString() is Boolean);
|
||||||
|
trace("//new CoercibleAsValue() is Boolean");
|
||||||
|
trace(new CoercibleAsValue() is Boolean);
|
||||||
|
trace("//new NotCoercibleAsValue() is Boolean");
|
||||||
|
trace(new NotCoercibleAsValue() is Boolean);
|
||||||
|
|
||||||
|
trace("// == String tests == ");
|
||||||
|
trace("//undefined is String");
|
||||||
|
trace(undefined is String);
|
||||||
|
trace("//null is String");
|
||||||
|
trace(null is String);
|
||||||
|
trace("//true is String");
|
||||||
|
trace(true is String);
|
||||||
|
trace("//false is String");
|
||||||
|
trace(false is String);
|
||||||
|
trace("//0 is String");
|
||||||
|
trace(0 is String);
|
||||||
|
trace("//1 is String");
|
||||||
|
trace(1 is String);
|
||||||
|
trace("//5.12 is String");
|
||||||
|
trace(5.12 is String);
|
||||||
|
trace("//(5.12 - .12) is String");
|
||||||
|
trace((5.12 - .12) is String);
|
||||||
|
trace("//-6 is String");
|
||||||
|
trace(-6 is String);
|
||||||
|
trace("//\"12.23\" is String");
|
||||||
|
trace("12.23" is String);
|
||||||
|
trace("//\"true\" is String");
|
||||||
|
trace("true" is String);
|
||||||
|
trace("//\"false\" is String");
|
||||||
|
trace("false" is String);
|
||||||
|
trace("//new CoercibleAsIntString() is String");
|
||||||
|
trace(new CoercibleAsIntString() is String);
|
||||||
|
trace("//new CoercibleAsNonIntString() is String");
|
||||||
|
trace(new CoercibleAsNonIntString() is String);
|
||||||
|
trace("//new CoercibleAsValue() is String");
|
||||||
|
trace(new CoercibleAsValue() is String);
|
||||||
|
trace("//new NotCoercibleAsValue() is String");
|
||||||
|
trace(new NotCoercibleAsValue() is String);
|
||||||
|
|
||||||
|
trace("// == Object tests == ");
|
||||||
|
trace("//undefined is Object");
|
||||||
|
trace(undefined is Object);
|
||||||
|
trace("//null is Object");
|
||||||
|
trace(null is Object);
|
||||||
|
trace("//true is Object");
|
||||||
|
trace(true is Object);
|
||||||
|
trace("//false is Object");
|
||||||
|
trace(false is Object);
|
||||||
|
trace("//0 is Object");
|
||||||
|
trace(0 is Object);
|
||||||
|
trace("//1 is Object");
|
||||||
|
trace(1 is Object);
|
||||||
|
trace("//5.12 is Object");
|
||||||
|
trace(5.12 is Object);
|
||||||
|
trace("//(5.12 - .12) is Object");
|
||||||
|
trace((5.12 - .12) is Object);
|
||||||
|
trace("//-6 is Object");
|
||||||
|
trace(-6 is Object);
|
||||||
|
trace("//\"12.23\" is Object");
|
||||||
|
trace("12.23" is Object);
|
||||||
|
trace("//\"true\" is Object");
|
||||||
|
trace("true" is Object);
|
||||||
|
trace("//\"false\" is Object");
|
||||||
|
trace("false" is Object);
|
||||||
|
trace("//new CoercibleAsIntString() is Object");
|
||||||
|
trace(new CoercibleAsIntString() is Object);
|
||||||
|
trace("//new CoercibleAsNonIntString() is Object");
|
||||||
|
trace(new CoercibleAsNonIntString() is Object);
|
||||||
|
trace("//new CoercibleAsValue() is Object");
|
||||||
|
trace(new CoercibleAsValue() is Object);
|
||||||
|
trace("//new NotCoercibleAsValue() is Object");
|
||||||
|
trace(new NotCoercibleAsValue() is Object);
|
|
@ -0,0 +1,198 @@
|
||||||
|
// == int tests ==
|
||||||
|
//undefined is int
|
||||||
|
false
|
||||||
|
//null is int
|
||||||
|
false
|
||||||
|
//true is int
|
||||||
|
false
|
||||||
|
//false is int
|
||||||
|
false
|
||||||
|
//0 is int
|
||||||
|
true
|
||||||
|
//1 is int
|
||||||
|
true
|
||||||
|
//5.12 is int
|
||||||
|
false
|
||||||
|
//(5.12 - .12) is int
|
||||||
|
true
|
||||||
|
//-6 is int
|
||||||
|
true
|
||||||
|
//"12.23" is int
|
||||||
|
false
|
||||||
|
//"true" is int
|
||||||
|
false
|
||||||
|
//"false" is int
|
||||||
|
false
|
||||||
|
//new CoercibleAsIntString() is int
|
||||||
|
false
|
||||||
|
//new CoercibleAsNonIntString() is int
|
||||||
|
false
|
||||||
|
//new CoercibleAsValue() is int
|
||||||
|
false
|
||||||
|
//new NotCoercibleAsValue() is int
|
||||||
|
false
|
||||||
|
// == uint tests ==
|
||||||
|
//undefined is uint
|
||||||
|
false
|
||||||
|
//null is uint
|
||||||
|
false
|
||||||
|
//true is uint
|
||||||
|
false
|
||||||
|
//false is uint
|
||||||
|
false
|
||||||
|
//0 is uint
|
||||||
|
true
|
||||||
|
//1 is uint
|
||||||
|
true
|
||||||
|
//5.12 is uint
|
||||||
|
false
|
||||||
|
//(5.12 - .12) is uint
|
||||||
|
true
|
||||||
|
//-6 is uint
|
||||||
|
false
|
||||||
|
//"12.23" is uint
|
||||||
|
false
|
||||||
|
//"true" is uint
|
||||||
|
false
|
||||||
|
//"false" is uint
|
||||||
|
false
|
||||||
|
//new CoercibleAsIntString() is uint
|
||||||
|
false
|
||||||
|
//new CoercibleAsNonIntString() is uint
|
||||||
|
false
|
||||||
|
//new CoercibleAsValue() is uint
|
||||||
|
false
|
||||||
|
//new NotCoercibleAsValue() is uint
|
||||||
|
false
|
||||||
|
// == Number tests ==
|
||||||
|
//undefined is Number
|
||||||
|
false
|
||||||
|
//null is Number
|
||||||
|
false
|
||||||
|
//true is Number
|
||||||
|
false
|
||||||
|
//false is Number
|
||||||
|
false
|
||||||
|
//0 is Number
|
||||||
|
true
|
||||||
|
//1 is Number
|
||||||
|
true
|
||||||
|
//5.12 is Number
|
||||||
|
true
|
||||||
|
//(5.12 - .12) is Number
|
||||||
|
true
|
||||||
|
//-6 is Number
|
||||||
|
true
|
||||||
|
//"12.23" is Number
|
||||||
|
false
|
||||||
|
//"true" is Number
|
||||||
|
false
|
||||||
|
//"false" is Number
|
||||||
|
false
|
||||||
|
//new CoercibleAsIntString() is Number
|
||||||
|
false
|
||||||
|
//new CoercibleAsNonIntString() is Number
|
||||||
|
false
|
||||||
|
//new CoercibleAsValue() is Number
|
||||||
|
false
|
||||||
|
//new NotCoercibleAsValue() is Number
|
||||||
|
false
|
||||||
|
// == Boolean tests ==
|
||||||
|
//undefined is Boolean
|
||||||
|
false
|
||||||
|
//null is Boolean
|
||||||
|
false
|
||||||
|
//true is Boolean
|
||||||
|
true
|
||||||
|
//false is Boolean
|
||||||
|
true
|
||||||
|
//0 is Boolean
|
||||||
|
false
|
||||||
|
//1 is Boolean
|
||||||
|
false
|
||||||
|
//5.12 is Boolean
|
||||||
|
false
|
||||||
|
//(5.12 - .12) is Boolean
|
||||||
|
false
|
||||||
|
//-6 is Boolean
|
||||||
|
false
|
||||||
|
//"12.23" is Boolean
|
||||||
|
false
|
||||||
|
//"true" is Boolean
|
||||||
|
false
|
||||||
|
//"false" is Boolean
|
||||||
|
false
|
||||||
|
//new CoercibleAsIntString() is Boolean
|
||||||
|
false
|
||||||
|
//new CoercibleAsNonIntString() is Boolean
|
||||||
|
false
|
||||||
|
//new CoercibleAsValue() is Boolean
|
||||||
|
false
|
||||||
|
//new NotCoercibleAsValue() is Boolean
|
||||||
|
false
|
||||||
|
// == String tests ==
|
||||||
|
//undefined is String
|
||||||
|
false
|
||||||
|
//null is String
|
||||||
|
false
|
||||||
|
//true is String
|
||||||
|
false
|
||||||
|
//false is String
|
||||||
|
false
|
||||||
|
//0 is String
|
||||||
|
false
|
||||||
|
//1 is String
|
||||||
|
false
|
||||||
|
//5.12 is String
|
||||||
|
false
|
||||||
|
//(5.12 - .12) is String
|
||||||
|
false
|
||||||
|
//-6 is String
|
||||||
|
false
|
||||||
|
//"12.23" is String
|
||||||
|
true
|
||||||
|
//"true" is String
|
||||||
|
true
|
||||||
|
//"false" is String
|
||||||
|
true
|
||||||
|
//new CoercibleAsIntString() is String
|
||||||
|
false
|
||||||
|
//new CoercibleAsNonIntString() is String
|
||||||
|
false
|
||||||
|
//new CoercibleAsValue() is String
|
||||||
|
false
|
||||||
|
//new NotCoercibleAsValue() is String
|
||||||
|
false
|
||||||
|
// == Object tests ==
|
||||||
|
//undefined is Object
|
||||||
|
false
|
||||||
|
//null is Object
|
||||||
|
false
|
||||||
|
//true is Object
|
||||||
|
true
|
||||||
|
//false is Object
|
||||||
|
true
|
||||||
|
//0 is Object
|
||||||
|
true
|
||||||
|
//1 is Object
|
||||||
|
true
|
||||||
|
//5.12 is Object
|
||||||
|
true
|
||||||
|
//(5.12 - .12) is Object
|
||||||
|
true
|
||||||
|
//-6 is Object
|
||||||
|
true
|
||||||
|
//"12.23" is Object
|
||||||
|
true
|
||||||
|
//"true" is Object
|
||||||
|
true
|
||||||
|
//"false" is Object
|
||||||
|
true
|
||||||
|
//new CoercibleAsIntString() is Object
|
||||||
|
true
|
||||||
|
//new CoercibleAsNonIntString() is Object
|
||||||
|
true
|
||||||
|
//new CoercibleAsValue() is Object
|
||||||
|
true
|
||||||
|
//new NotCoercibleAsValue() is Object
|
||||||
|
true
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue