Browse Source

Make `Array.prototype` methods spec compliant (#1449)

pull/1455/head
Halid Odat 3 years ago committed by GitHub
parent
commit
b55b2af801
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1015
      boa/src/builtins/array/mod.rs
  2. 18
      boa/src/builtins/array/tests.rs
  3. 20
      boa/src/builtins/iterable/mod.rs
  4. 10
      boa/src/property/mod.rs
  5. 11
      boa/src/value/conversions.rs
  6. 35
      boa/src/value/mod.rs

1015
boa/src/builtins/array/mod.rs

File diff suppressed because it is too large Load Diff

18
boa/src/builtins/array/tests.rs

@ -1077,7 +1077,7 @@ fn reduce() {
);
assert_eq!(
result,
"\"Reduce was called on an empty array and with no initial value\""
"\"Array.prototype.reduce: called on an empty array and with no initial value\""
);
// Array with no defined elements
@ -1096,7 +1096,7 @@ fn reduce() {
);
assert_eq!(
result,
"\"Reduce was called on an empty array and with no initial value\""
"\"Array.prototype.reduce: called on an empty array and with no initial value\""
);
// No callback
@ -1110,7 +1110,10 @@ fn reduce() {
}
"#,
);
assert_eq!(result, "\"Reduce was called without a callback\"");
assert_eq!(
result,
"\"Array.prototype.reduce: callback function is not callable\""
);
}
#[test]
@ -1199,7 +1202,7 @@ fn reduce_right() {
);
assert_eq!(
result,
"\"reduceRight was called on an empty array and with no initial value\""
"\"Array.prototype.reduceRight: called on an empty array and with no initial value\""
);
// Array with no defined elements
@ -1218,7 +1221,7 @@ fn reduce_right() {
);
assert_eq!(
result,
"\"reduceRight was called on an empty array and with no initial value\""
"\"Array.prototype.reduceRight: called on an empty array and with no initial value\""
);
// No callback
@ -1232,7 +1235,10 @@ fn reduce_right() {
}
"#,
);
assert_eq!(result, "\"reduceRight was called without a callback\"");
assert_eq!(
result,
"\"Array.prototype.reduceRight: callback function is not callable\""
);
}
#[test]

20
boa/src/builtins/iterable/mod.rs

@ -5,7 +5,6 @@ use crate::{
SetIterator,
},
object::{GcObject, ObjectInitializer},
property::{Attribute, DataDescriptor},
symbol::WellKnownSymbols,
BoaProfiler, Context, Result, Value,
};
@ -87,13 +86,18 @@ impl IteratorPrototypes {
///
/// Generates an object supporting the IteratorResult interface.
pub fn create_iter_result_object(context: &mut Context, value: Value, done: bool) -> Value {
let object = Value::new_object(context);
// TODO: Fix attributes of value and done
let value_property = DataDescriptor::new(value, Attribute::all());
let done_property = DataDescriptor::new(done, Attribute::all());
object.set_property("value", value_property);
object.set_property("done", done_property);
object
// 1. Assert: Type(done) is Boolean.
// 2. Let obj be ! OrdinaryObjectCreate(%Object.prototype%).
let obj = context.construct_object();
// 3. Perform ! CreateDataPropertyOrThrow(obj, "value", value).
obj.create_data_property_or_throw("value", value, context)
.unwrap();
// 4. Perform ! CreateDataPropertyOrThrow(obj, "done", done).
obj.create_data_property_or_throw("done", done, context)
.unwrap();
// 5. Return obj.
obj.into()
}
/// Get an iterator record

10
boa/src/property/mod.rs

@ -452,6 +452,16 @@ impl From<usize> for PropertyKey {
}
}
impl From<i64> for PropertyKey {
fn from(value: i64) -> Self {
if let Ok(index) = u32::try_from(value) {
PropertyKey::Index(index)
} else {
PropertyKey::String(JsString::from(value.to_string()))
}
}
}
impl From<u64> for PropertyKey {
fn from(value: u64) -> Self {
if let Ok(index) = u32::try_from(value) {

11
boa/src/value/conversions.rs

@ -121,6 +121,17 @@ impl From<u64> for Value {
}
}
impl From<i64> for Value {
#[inline]
fn from(value: i64) -> Value {
if let Ok(value) = i32::try_from(value) {
Value::integer(value)
} else {
Value::rational(value as f64)
}
}
}
impl From<bool> for Value {
#[inline]
fn from(value: bool) -> Self {

35
boa/src/value/mod.rs

@ -265,7 +265,7 @@ impl Value {
///
/// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal> would turn `extensible` to `false`
/// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze> would also turn `extensible` to `false`
pub fn is_extensible(&self) -> bool {
pub(crate) fn is_extensible(&self) -> bool {
true
}
@ -422,7 +422,7 @@ impl Value {
/// Removes a property from a Value object.
///
/// It will return a boolean based on if the value was removed, if there was no value to remove false is returned.
pub fn remove_property<Key>(&self, key: Key) -> bool
pub(crate) fn remove_property<Key>(&self, key: Key) -> bool
where
Key: Into<PropertyKey>,
{
@ -432,7 +432,7 @@ impl Value {
/// Resolve the property in the object.
///
/// A copy of the Property is returned.
pub fn get_property<Key>(&self, key: Key) -> Option<PropertyDescriptor>
pub(crate) fn get_property<Key>(&self, key: Key) -> Option<PropertyDescriptor>
where
Key: Into<PropertyKey>,
{
@ -453,7 +453,7 @@ impl Value {
/// Resolve the property in the object and get its value, or undefined if this is not an object or the field doesn't exist
/// get_field receives a Property from get_prop(). It should then return the `[[Get]]` result value if that's set, otherwise fall back to `[[Value]]`
pub fn get_field<K>(&self, key: K, context: &mut Context) -> Result<Self>
pub(crate) fn get_field<K>(&self, key: K, context: &mut Context) -> Result<Self>
where
K: Into<PropertyKey>,
{
@ -468,7 +468,7 @@ impl Value {
/// Check to see if the Value has the field, mainly used by environment records.
#[inline]
pub fn has_field<K>(&self, key: K) -> bool
pub(crate) fn has_field<K>(&self, key: K) -> bool
where
K: Into<PropertyKey>,
{
@ -487,7 +487,7 @@ impl Value {
///
/// [spec]: https://tc39.es/ecma262/#sec-set-o-p-v-throw
#[inline]
pub fn set_field<K, V>(
pub(crate) fn set_field<K, V>(
&self,
key: K,
value: V,
@ -534,7 +534,7 @@ impl Value {
/// Set the property in the value.
#[inline]
pub fn set_property<K, P>(&self, key: K, property: P)
pub(crate) fn set_property<K, P>(&self, key: K, property: P)
where
K: Into<PropertyKey>,
P: Into<PropertyDescriptor>,
@ -962,6 +962,27 @@ impl Value {
}
}
}
/// Check if it is an array.
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-isarray
pub(crate) fn is_array(&self, _context: &mut Context) -> Result<bool> {
// 1. If Type(argument) is not Object, return false.
if let Some(object) = self.as_object() {
// 2. If argument is an Array exotic object, return true.
// a. If argument.[[ProxyHandler]] is null, throw a TypeError exception.
// 3. If argument is a Proxy exotic object, then
// b. Let target be argument.[[ProxyTarget]].
// c. Return ? IsArray(target).
// 4. Return false.
Ok(object.is_array())
} else {
Ok(false)
}
}
}
impl Default for Value {

Loading…
Cancel
Save