From 82e8a1197a961190e3c1751b8bab8890f39ae8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaros=C5=82aw=20Konik?= Date: Sun, 30 May 2021 19:49:02 +0200 Subject: [PATCH] Support GetOwnProperty for string exotic object (#1291) * Support GetOwnProperty for string exotic object * Fix clippy error * change var name * dont load from_u32 to namespace * be explicit about attributes * Update boa/src/object/internal_methods.rs Co-authored-by: Iban Eguia * fix utf16 emoji panic * use map and ? operator Co-authored-by: Iban Eguia --- boa/src/builtins/string/tests.rs | 11 +++++ boa/src/object/internal_methods.rs | 69 ++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/boa/src/builtins/string/tests.rs b/boa/src/builtins/string/tests.rs index 0e5f079160..dea218708f 100644 --- a/boa/src/builtins/string/tests.rs +++ b/boa/src/builtins/string/tests.rs @@ -1093,3 +1093,14 @@ fn unicode_iter() { assert_eq!(forward(&mut context, "next.value"), "undefined"); assert_eq!(forward(&mut context, "next.done"), "true"); } + +#[test] +fn string_get_property() { + let mut context = Context::new(); + assert_eq!(forward(&mut context, "'abc'[-1]"), "undefined"); + assert_eq!(forward(&mut context, "'abc'[1]"), "\"b\""); + assert_eq!(forward(&mut context, "'abc'[2]"), "\"c\""); + assert_eq!(forward(&mut context, "'abc'[3]"), "undefined"); + assert_eq!(forward(&mut context, "'abc'['foo']"), "undefined"); + assert_eq!(forward(&mut context, "'😀'[0]"), "\"\\ud83d\""); +} diff --git a/boa/src/object/internal_methods.rs b/boa/src/object/internal_methods.rs index 80246e0a55..0e522e3a5e 100644 --- a/boa/src/object/internal_methods.rs +++ b/boa/src/object/internal_methods.rs @@ -390,6 +390,71 @@ impl GcObject { } } + /// Gets own property of 'Object' + /// + #[inline] + pub fn get_own_property(&self, key: &PropertyKey) -> Option { + let _timer = BoaProfiler::global().start_event("Object::get_own_property", "object"); + + let object = self.borrow(); + match object.data { + ObjectData::String(_) => self.string_exotic_get_own_property(key), + _ => self.ordinary_get_own_property(key), + } + } + + /// StringGetOwnProperty abstract operation + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-stringgetownproperty + #[inline] + pub fn string_get_own_property(&self, key: &PropertyKey) -> Option { + let object = self.borrow(); + + match key { + PropertyKey::Index(index) => { + let string = object.as_string().unwrap(); + let pos = *index as usize; + + if pos >= string.len() { + return None; + } + + let result_str = string.encode_utf16().nth(pos).map(|utf16_val| { + char::from_u32(u32::from(utf16_val)) + .map_or_else(|| Value::from(format!("\\u{:x}", utf16_val)), Value::from) + })?; + + let desc = PropertyDescriptor::from(DataDescriptor::new( + result_str, + Attribute::READONLY | Attribute::ENUMERABLE | Attribute::PERMANENT, + )); + + Some(desc) + } + _ => None, + } + } + + /// Gets own property of 'String' exotic object + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-string-exotic-objects-getownproperty-p + #[inline] + pub fn string_exotic_get_own_property(&self, key: &PropertyKey) -> Option { + let desc = self.ordinary_get_own_property(key); + + if desc.is_some() { + desc + } else { + self.string_get_own_property(key) + } + } + /// The specification returns a Property Descriptor or Undefined. /// /// These are 2 separate types and we can't do that here. @@ -399,9 +464,7 @@ impl GcObject { /// /// [spec]: https://tc39.es/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-getownproperty-p #[inline] - pub fn get_own_property(&self, key: &PropertyKey) -> Option { - let _timer = BoaProfiler::global().start_event("Object::get_own_property", "object"); - + pub fn ordinary_get_own_property(&self, key: &PropertyKey) -> Option { let object = self.borrow(); let property = match key { PropertyKey::Index(index) => object.indexed_properties.get(&index),