Allow no-hint primitive coercion
This commit is contained in:
parent
76ab8570e4
commit
2ef03c6019
|
@ -486,10 +486,10 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
Op::IfFalse { offset } => self.op_if_false(offset, reader),
|
Op::IfFalse { offset } => self.op_if_false(offset, reader),
|
||||||
Op::IfStrictEq { offset } => self.op_if_strict_eq(offset, reader),
|
Op::IfStrictEq { offset } => self.op_if_strict_eq(offset, reader),
|
||||||
Op::IfStrictNe { offset } => self.op_if_strict_ne(offset, reader),
|
Op::IfStrictNe { offset } => self.op_if_strict_ne(offset, reader),
|
||||||
Op::IfEq { offset } => self.op_if_eq(context, offset, reader),
|
Op::IfEq { offset } => self.op_if_eq(offset, reader),
|
||||||
Op::IfNe { offset } => self.op_if_ne(context, offset, reader),
|
Op::IfNe { offset } => self.op_if_ne(offset, reader),
|
||||||
Op::StrictEquals => self.op_strict_equals(),
|
Op::StrictEquals => self.op_strict_equals(),
|
||||||
Op::Equals => self.op_equals(context),
|
Op::Equals => self.op_equals(),
|
||||||
Op::Not => self.op_not(),
|
Op::Not => self.op_not(),
|
||||||
Op::HasNext => self.op_has_next(),
|
Op::HasNext => self.op_has_next(),
|
||||||
Op::HasNext2 {
|
Op::HasNext2 {
|
||||||
|
@ -1450,14 +1450,13 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
|
|
||||||
fn op_if_eq(
|
fn op_if_eq(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
|
||||||
offset: i32,
|
offset: i32,
|
||||||
reader: &mut Reader<Cursor<&[u8]>>,
|
reader: &mut Reader<Cursor<&[u8]>>,
|
||||||
) -> Result<FrameControl<'gc>, Error> {
|
) -> Result<FrameControl<'gc>, Error> {
|
||||||
let value2 = self.avm2.pop();
|
let value2 = self.context.avm2.pop();
|
||||||
let value1 = self.avm2.pop();
|
let value1 = self.context.avm2.pop();
|
||||||
|
|
||||||
if value1.abstract_eq(&value2, self, context)? {
|
if value1.abstract_eq(&value2, self)? {
|
||||||
reader.seek(offset as i64)?;
|
reader.seek(offset as i64)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1466,14 +1465,13 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
|
|
||||||
fn op_if_ne(
|
fn op_if_ne(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
|
||||||
offset: i32,
|
offset: i32,
|
||||||
reader: &mut Reader<Cursor<&[u8]>>,
|
reader: &mut Reader<Cursor<&[u8]>>,
|
||||||
) -> Result<FrameControl<'gc>, Error> {
|
) -> Result<FrameControl<'gc>, Error> {
|
||||||
let value2 = self.avm2.pop();
|
let value2 = self.context.avm2.pop();
|
||||||
let value1 = self.avm2.pop();
|
let value1 = self.context.avm2.pop();
|
||||||
|
|
||||||
if !value1.abstract_eq(&value2, self, context)? {
|
if !value1.abstract_eq(&value2, self)? {
|
||||||
reader.seek(offset as i64)?;
|
reader.seek(offset as i64)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1489,16 +1487,13 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_equals(
|
fn op_equals(&mut self) -> Result<FrameControl<'gc>, Error> {
|
||||||
&mut self,
|
let value2 = self.context.avm2.pop();
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
let value1 = self.context.avm2.pop();
|
||||||
) -> Result<FrameControl<'gc>, Error> {
|
|
||||||
let value2 = self.avm2.pop();
|
|
||||||
let value1 = self.avm2.pop();
|
|
||||||
|
|
||||||
let result = value1.abstract_eq(&value2, self, context)?;
|
let result = value1.abstract_eq(&value2, self)?;
|
||||||
|
|
||||||
self.avm2.push(result);
|
self.context.avm2.push(result);
|
||||||
|
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,9 +278,12 @@ impl<'gc> Value<'gc> {
|
||||||
/// ToPrimitive algorithm which appears to match AVM2.
|
/// ToPrimitive algorithm which appears to match AVM2.
|
||||||
pub fn coerce_to_primitive(
|
pub fn coerce_to_primitive(
|
||||||
&self,
|
&self,
|
||||||
hint: Hint,
|
hint: Option<Hint>,
|
||||||
activation: &mut Activation<'_, 'gc, '_>,
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
) -> Result<Value<'gc>, Error> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
|
// TODO: `Date` is default-hinted as a `String` for some reason
|
||||||
|
let hint = hint.unwrap_or(Hint::Number);
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Value::Object(o) if hint == Hint::String => {
|
Value::Object(o) if hint == Hint::String => {
|
||||||
let mut prim = self.clone();
|
let mut prim = self.clone();
|
||||||
|
@ -408,7 +411,7 @@ impl<'gc> Value<'gc> {
|
||||||
))
|
))
|
||||||
.coerce_to_number(activation)?,
|
.coerce_to_number(activation)?,
|
||||||
Value::Object(_) => self
|
Value::Object(_) => self
|
||||||
.coerce_to_primitive(Hint::Number, activation)?
|
.coerce_to_primitive(Some(Hint::Number), activation)?
|
||||||
.coerce_to_number(activation)?,
|
.coerce_to_number(activation)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -517,7 +520,7 @@ impl<'gc> Value<'gc> {
|
||||||
Value::String(s) => *s,
|
Value::String(s) => *s,
|
||||||
Value::Namespace(ns) => ns.as_uri(),
|
Value::Namespace(ns) => ns.as_uri(),
|
||||||
Value::Object(_) => self
|
Value::Object(_) => self
|
||||||
.coerce_to_primitive(Hint::String, activation)?
|
.coerce_to_primitive(Some(Hint::String), activation)?
|
||||||
.coerce_to_string(activation)?,
|
.coerce_to_string(activation)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -546,8 +549,7 @@ impl<'gc> Value<'gc> {
|
||||||
pub fn abstract_eq(
|
pub fn abstract_eq(
|
||||||
&self,
|
&self,
|
||||||
other: &Value<'gc>,
|
other: &Value<'gc>,
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Undefined, Value::Undefined) => Ok(true),
|
(Value::Undefined, Value::Undefined) => Ok(true),
|
||||||
|
@ -573,49 +575,48 @@ impl<'gc> Value<'gc> {
|
||||||
(Value::Undefined, Value::Null) => Ok(true),
|
(Value::Undefined, Value::Null) => Ok(true),
|
||||||
(Value::Null, Value::Undefined) => Ok(true),
|
(Value::Null, Value::Undefined) => Ok(true),
|
||||||
(Value::Number(_), Value::String(_)) => {
|
(Value::Number(_), Value::String(_)) => {
|
||||||
let number_other = Value::from(other.coerce_to_number(activation, context)?);
|
let number_other = Value::from(other.coerce_to_number(activation)?);
|
||||||
|
|
||||||
self.abstract_eq(&number_other, activation, context)
|
self.abstract_eq(&number_other, activation)
|
||||||
}
|
}
|
||||||
(Value::String(_), Value::Number(_)) => {
|
(Value::String(_), Value::Number(_)) => {
|
||||||
let number_self = Value::from(self.coerce_to_number(activation, context)?);
|
let number_self = Value::from(self.coerce_to_number(activation)?);
|
||||||
|
|
||||||
number_self.abstract_eq(other, activation, context)
|
number_self.abstract_eq(other, activation)
|
||||||
}
|
}
|
||||||
(Value::Bool(_), _) => {
|
(Value::Bool(_), _) => {
|
||||||
let number_self = Value::from(self.coerce_to_number(activation, context)?);
|
let number_self = Value::from(self.coerce_to_number(activation)?);
|
||||||
|
|
||||||
number_self.abstract_eq(other, activation, context)
|
number_self.abstract_eq(other, activation)
|
||||||
}
|
}
|
||||||
(_, Value::Bool(_)) => {
|
(_, Value::Bool(_)) => {
|
||||||
let number_other = Value::from(other.coerce_to_number(activation, context)?);
|
let number_other = Value::from(other.coerce_to_number(activation)?);
|
||||||
|
|
||||||
self.abstract_eq(&number_other, activation, context)
|
self.abstract_eq(&number_other, activation)
|
||||||
}
|
}
|
||||||
(Value::String(_), Value::Object(_)) | (Value::Number(_), Value::Object(_)) => {
|
(Value::String(_), Value::Object(_)) | (Value::Number(_), Value::Object(_)) => {
|
||||||
//TODO: Should this be `Hint::Number`, `Hint::String`, or no-hint?
|
//TODO: Should this be `Hint::Number`, `Hint::String`, or no-hint?
|
||||||
let primitive_other =
|
let primitive_other = other.coerce_to_primitive(Some(Hint::Number), activation)?;
|
||||||
other.coerce_to_primitive(Hint::Number, activation, context)?;
|
|
||||||
|
|
||||||
self.abstract_eq(&primitive_other, activation, context)
|
self.abstract_eq(&primitive_other, activation)
|
||||||
}
|
}
|
||||||
(Value::Object(_), Value::String(_)) | (Value::Object(_), Value::Number(_)) => {
|
(Value::Object(_), Value::String(_)) | (Value::Object(_), Value::Number(_)) => {
|
||||||
//TODO: Should this be `Hint::Number`, `Hint::String`, or no-hint?
|
//TODO: Should this be `Hint::Number`, `Hint::String`, or no-hint?
|
||||||
let primitive_self = self.coerce_to_primitive(Hint::Number, activation, context)?;
|
let primitive_self = self.coerce_to_primitive(Some(Hint::Number), activation)?;
|
||||||
|
|
||||||
primitive_self.abstract_eq(other, activation, context)
|
primitive_self.abstract_eq(other, activation)
|
||||||
}
|
}
|
||||||
//TODO: This is entirely a shot in the dark.
|
//TODO: This is entirely a shot in the dark.
|
||||||
(Value::Namespace(_), _) => {
|
(Value::Namespace(_), _) => {
|
||||||
let string_self = self.coerce_to_primitive(Hint::String, activation, context)?;
|
let string_self = self.coerce_to_primitive(Some(Hint::String), activation)?;
|
||||||
|
|
||||||
string_self.abstract_eq(other, activation, context)
|
string_self.abstract_eq(other, activation)
|
||||||
}
|
}
|
||||||
//TODO: So is this.
|
//TODO: So is this.
|
||||||
(_, Value::Namespace(_)) => {
|
(_, Value::Namespace(_)) => {
|
||||||
let string_other = other.coerce_to_primitive(Hint::String, activation, context)?;
|
let string_other = other.coerce_to_primitive(Some(Hint::String), activation)?;
|
||||||
|
|
||||||
self.abstract_eq(&string_other, activation, context)
|
self.abstract_eq(&string_other, activation)
|
||||||
}
|
}
|
||||||
_ => Ok(false),
|
_ => Ok(false),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue