Skip to content

Commit

Permalink
Implement Array.prototype.filter
Browse files Browse the repository at this point in the history
  • Loading branch information
Nickforall committed Mar 9, 2020
1 parent 9766409 commit 987a1bd
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 0 deletions.
42 changes: 42 additions & 0 deletions boa/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,47 @@ pub fn slice(this: &Value, args: &[Value], interpreter: &mut Interpreter) -> Res
Ok(new_array)
}

/// Array.prototype.filter ( callback, [ thisArg ] )
///
/// For each element in the array the callback function is called, and a new
/// array is constructed for every value whose callback returned a truthy value
/// <https://tc39.es/ecma262/#sec-array.prototype.filter>
pub fn filter(this: &Value, args: &[Value], interpreter: &mut Interpreter) -> ResultValue {
if args.is_empty() {
return Err(to_value(
"missing argument 0 when calling function Array.prototype.filter",
));
}

let callback = args.get(0).cloned().unwrap_or_else(undefined);
let this_val = args.get(1).cloned().unwrap_or_else(undefined);

let length: i32 =
from_value(this.get_field_slice("length")).expect("Could not get `length` property.");

let new = new_array(&interpreter)?;

let values = (0..length)
.filter_map(|idx| {
let element = this.get_field_slice(&idx.to_string());

let args = vec![element.clone(), to_value(idx), new.clone()];

let callback_result = interpreter
.call(&callback, &this_val, args)
.unwrap_or_else(|_| undefined());

if callback_result.is_true() {
Some(element)
} else {
None
}
})
.collect::<Vec<Value>>();

construct_array(&new, &values)
}

/// Create a new `Array` object
pub fn create_constructor(global: &Value) -> Value {
// Create Constructor
Expand All @@ -760,6 +801,7 @@ pub fn create_constructor(global: &Value) -> Value {
make_builtin_fn!(map, named "map", with length 1, of array_prototype);
make_builtin_fn!(fill, named "fill", with length 1, of array_prototype);
make_builtin_fn!(for_each, named "forEach", with length 1, of array_prototype);
make_builtin_fn!(filter, named "filter", with length 1, of array_prototype);
make_builtin_fn!(pop, named "pop", of array_prototype);
make_builtin_fn!(join, named "join", with length 1, of array_prototype);
make_builtin_fn!(to_string, named "toString", of array_prototype);
Expand Down
66 changes: 66 additions & 0 deletions boa/src/builtins/array/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -675,3 +675,69 @@ fn for_each_push_value() {
assert_eq!(forward(&mut engine, "a[6]"), "6");
assert_eq!(forward(&mut engine, "a[7]"), "8");
}

fn filter() {
let realm = Realm::create();
let mut engine = Executor::new(realm);

let js = r#"
var empty = [];
var one = ["1"];
var many = ["1", "0", "1"];
var empty_filtered = empty.filter(v => v === "1");
var one_filtered = one.filter(v => v === "1");
var zero_filtered = one.filter(v => v === "0");
var many_one_filtered = many.filter(v => v === "1");
var many_zero_filtered = many.filter(v => v === "0");
"#;

forward(&mut engine, js);

// assert the old arrays have not been modified
assert_eq!(forward(&mut engine, "one[0]"), String::from("1"));
assert_eq!(
forward(&mut engine, "many[2] + many[1] + many[0]"),
String::from("101")
);

// NB: These tests need to be rewritten once `Display` has been implemented for `Array`
// Empty
assert_eq!(
forward(&mut engine, "empty_filtered.length"),
String::from("0")
);

// One filtered on "1"
assert_eq!(
forward(&mut engine, "one_filtered.length"),
String::from("1")
);
assert_eq!(forward(&mut engine, "one_filtered[0]"), String::from("1"));

// One filtered on "0"
assert_eq!(
forward(&mut engine, "zero_filtered.length"),
String::from("0")
);

// Many filtered on "1"
assert_eq!(
forward(&mut engine, "many_one_filtered.length"),
String::from("2")
);
assert_eq!(
forward(&mut engine, "many_one_filtered[0] + many_one_filtered[1]"),
String::from("11")
);

// Many filtered on "0"
assert_eq!(
forward(&mut engine, "many_zero_filtered.length"),
String::from("1")
);
assert_eq!(
forward(&mut engine, "many_zero_filtered[0]"),
String::from("0")
);
}

0 comments on commit 987a1bd

Please sign in to comment.