Impl `propertyIsEnumerable`

This commit is contained in:
David Wendt 2020-03-07 20:16:48 -05:00
parent a0ca5891e4
commit 2afbcf450a
4 changed files with 45 additions and 0 deletions

View File

@ -571,6 +571,10 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
self.0.read().base.get_enumerant_name(index) self.0.read().base.get_enumerant_name(index)
} }
fn property_is_enumerable(&self, name: &QName) -> bool {
self.0.read().base.property_is_enumerable(name)
}
fn as_ptr(&self) -> *const ObjectPtr { fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr self.0.as_ptr() as *const ObjectPtr
} }

View File

@ -64,6 +64,28 @@ pub fn is_prototype_of<'gc>(
Ok(false.into()) Ok(false.into())
} }
/// `Object.prototype.propertyIsEnumerable`
pub fn property_is_enumerable<'gc>(
_avm: &mut Avm2<'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
this: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error> {
let this: Result<Object<'gc>, Error> = this.ok_or_else(|| "No valid this parameter".into());
let this = this?;
let name: Result<&Value<'gc>, Error> = args.get(0).ok_or_else(|| "No name specified".into());
let name = name?.as_string()?;
if let Some(ns) = this.resolve_any(&name)? {
if !ns.is_private() {
let qname = QName::new(ns, &name);
return Ok(this.property_is_enumerable(&qname).into());
}
}
Ok(false.into())
}
/// Partially construct `Object.prototype`. /// Partially construct `Object.prototype`.
/// ///
/// `__proto__` and other cross-linked properties of this object will *not* /// `__proto__` and other cross-linked properties of this object will *not*
@ -90,4 +112,10 @@ pub fn fill_proto<'gc>(
0, 0,
FunctionObject::from_builtin(gc_context, is_prototype_of, fn_proto), FunctionObject::from_builtin(gc_context, is_prototype_of, fn_proto),
); );
object_proto.install_method(
gc_context,
QName::new(Namespace::public_namespace(), "propertyIsEnumerable"),
0,
FunctionObject::from_builtin(gc_context, property_is_enumerable, fn_proto),
);
} }

View File

@ -352,6 +352,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// mechanism. /// mechanism.
fn get_enumerant_name(&self, index: u32) -> Option<QName>; fn get_enumerant_name(&self, index: u32) -> Option<QName>;
/// Determine if a property is currently enumerable.
///
/// Properties that do not exist are also not enumerable.
fn property_is_enumerable(&self, name: &QName) -> bool;
/// Install a method (or any other non-slot value) on an object. /// Install a method (or any other non-slot value) on an object.
fn install_method( fn install_method(
&mut self, &mut self,

View File

@ -202,6 +202,10 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
self.0.read().get_enumerant_name(index) self.0.read().get_enumerant_name(index)
} }
fn property_is_enumerable(&self, name: &QName) -> bool {
self.0.read().property_is_enumerable(name)
}
fn as_ptr(&self) -> *const ObjectPtr { fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr self.0.as_ptr() as *const ObjectPtr
} }
@ -750,6 +754,10 @@ impl<'gc> ScriptObjectData<'gc> {
self.enumerants.get(true_index).cloned() self.enumerants.get(true_index).cloned()
} }
pub fn property_is_enumerable(&self, name: &QName) -> bool {
self.enumerants.contains(name)
}
/// Install a method into the object. /// Install a method into the object.
pub fn install_method(&mut self, name: QName, disp_id: u32, function: Object<'gc>) { pub fn install_method(&mut self, name: QName, disp_id: u32, function: Object<'gc>) {
if disp_id > 0 { if disp_id > 0 {