Implement `isPropertyEnumerable` and `isPrototypeOf`.
This commit is contained in:
parent
aa7997b658
commit
b4e9b8442e
|
@ -1433,11 +1433,13 @@ impl<'gc> Avm1<'gc> {
|
|||
|
||||
let constructor = object
|
||||
.read()
|
||||
.get(&method_name.as_string()?, self, context, object.to_owned())
|
||||
.get(&method_name.as_string()?, self, context, object.to_owned())?
|
||||
.resolve(self, context)?
|
||||
.as_object()?;
|
||||
let proto = constructor
|
||||
.read()
|
||||
.get("prototype", self, context, constructor.to_owned());
|
||||
.get("prototype", self, context, constructor.to_owned())?
|
||||
.resolve(self, context)?;
|
||||
let this = GcCell::allocate(
|
||||
context.gc_context,
|
||||
Object::object(
|
||||
|
@ -1447,7 +1449,10 @@ impl<'gc> Avm1<'gc> {
|
|||
);
|
||||
|
||||
//TODO: What happens if you `ActionNewMethod` without a method name?
|
||||
constructor.read().call(self, context, this, &args);
|
||||
constructor
|
||||
.read()
|
||||
.call(self, context, this, &args)?
|
||||
.ignore();
|
||||
|
||||
//TODO: The SWF docs are really cagey about what the hell happens with
|
||||
//user defined constructors... do we need stack continuations?!
|
||||
|
@ -1470,11 +1475,13 @@ impl<'gc> Avm1<'gc> {
|
|||
.unwrap()
|
||||
.clone()
|
||||
.read()
|
||||
.resolve(fn_name.as_string()?, self, context)
|
||||
.resolve(fn_name.as_string()?, self, context)?
|
||||
.resolve(self, context)?
|
||||
.as_object()?;
|
||||
let proto = constructor
|
||||
.read()
|
||||
.get("prototype", self, context, constructor.to_owned());
|
||||
.get("prototype", self, context, constructor.to_owned())?
|
||||
.resolve(self, context)?;
|
||||
let this = GcCell::allocate(
|
||||
context.gc_context,
|
||||
Object::object(
|
||||
|
@ -1483,7 +1490,10 @@ impl<'gc> Avm1<'gc> {
|
|||
),
|
||||
);
|
||||
|
||||
constructor.read().call(self, context, this, &args);
|
||||
constructor
|
||||
.read()
|
||||
.call(self, context, this, &args)?
|
||||
.ignore();
|
||||
|
||||
self.push(Value::Undefined);
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ pub fn add_property<'gc>(
|
|||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: GcCell<'gc, Object<'gc>>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Value<'gc> {
|
||||
) -> Result<ReturnValue<'gc>, Error> {
|
||||
let name = args.get(0).unwrap_or(&Value::Undefined);
|
||||
let getter = args.get(1).unwrap_or(&Value::Undefined);
|
||||
let setter = args.get(2).unwrap_or(&Value::Undefined);
|
||||
|
@ -29,19 +29,19 @@ pub fn add_property<'gc>(
|
|||
EnumSet::empty(),
|
||||
);
|
||||
} else {
|
||||
return Value::Bool(false);
|
||||
return Ok(false.into());
|
||||
}
|
||||
} else if let Value::Null = setter {
|
||||
this.write(context.gc_context)
|
||||
.force_set_virtual(name, get_func, None, ReadOnly);
|
||||
} else {
|
||||
return Value::Bool(false);
|
||||
return Ok(false.into());
|
||||
}
|
||||
}
|
||||
|
||||
Value::Bool(false)
|
||||
Ok(false.into())
|
||||
}
|
||||
_ => Value::Bool(false),
|
||||
_ => Ok(false.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,46 @@ fn to_string<'gc>(
|
|||
Ok(ReturnValue::Immediate("[Object object]".into()))
|
||||
}
|
||||
|
||||
/// Implements `Object.prototype.isPropertyEnumerable`
|
||||
fn is_property_enumerable<'gc>(
|
||||
_: &mut Avm1<'gc>,
|
||||
_: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: GcCell<'gc, Object<'gc>>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error> {
|
||||
match args.get(0) {
|
||||
Some(Value::String(name)) => {
|
||||
Ok(Value::Bool(this.read().is_property_enumerable(name)).into())
|
||||
}
|
||||
_ => Ok(Value::Bool(false).into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements `Object.prototype.isPrototypeOf`
|
||||
fn is_prototype_of<'gc>(
|
||||
_: &mut Avm1<'gc>,
|
||||
_: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: GcCell<'gc, Object<'gc>>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error> {
|
||||
match args.get(0) {
|
||||
Some(Value::Object(ob)) => {
|
||||
let mut proto = ob.read().prototype().cloned();
|
||||
|
||||
while let Some(proto_ob) = proto {
|
||||
if GcCell::ptr_eq(this, proto_ob) {
|
||||
return Ok(Value::Bool(true).into());
|
||||
}
|
||||
|
||||
proto = proto_ob.read().prototype().cloned();
|
||||
}
|
||||
|
||||
Ok(Value::Bool(false).into())
|
||||
}
|
||||
_ => Ok(Value::Bool(false).into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Partially construct `Object.prototype`.
|
||||
///
|
||||
/// `__proto__` and other cross-linked properties of this object will *not*
|
||||
|
@ -88,14 +128,28 @@ pub fn fill_proto<'gc>(
|
|||
"addProperty",
|
||||
add_property,
|
||||
gc_context,
|
||||
EnumSet::empty(),
|
||||
DontDelete | DontEnum,
|
||||
Some(fn_proto),
|
||||
);
|
||||
ob_proto_write.force_set_function(
|
||||
"hasOwnProperty",
|
||||
has_own_property,
|
||||
gc_context,
|
||||
EnumSet::empty(),
|
||||
DontDelete | DontEnum,
|
||||
Some(fn_proto),
|
||||
);
|
||||
ob_proto_write.force_set_function(
|
||||
"isPropertyEnumerable",
|
||||
is_property_enumerable,
|
||||
gc_context,
|
||||
DontDelete | DontEnum,
|
||||
Some(fn_proto),
|
||||
);
|
||||
ob_proto_write.force_set_function(
|
||||
"isPrototypeOf",
|
||||
is_prototype_of,
|
||||
gc_context,
|
||||
DontDelete | DontEnum,
|
||||
Some(fn_proto),
|
||||
);
|
||||
ob_proto_write.force_set_function(
|
||||
|
|
|
@ -389,6 +389,14 @@ impl<'gc> Object<'gc> {
|
|||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn is_property_enumerable(&self, name: &str) -> bool {
|
||||
if let Some(prop) = self.values.get(name) {
|
||||
prop.is_enumerable()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_keys(&self) -> Vec<String> {
|
||||
self.values
|
||||
.iter()
|
||||
|
@ -435,7 +443,7 @@ impl<'gc> Object<'gc> {
|
|||
/// Returns a copy of a given function.
|
||||
///
|
||||
/// TODO: We have to clone here because of how executables are stored on
|
||||
/// objects. This might not be a good idea for performance.
|
||||
/// objects directly. This might not be a good idea for performance.
|
||||
pub fn as_executable(&self) -> Option<Executable<'gc>> {
|
||||
self.function.clone()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue