-
-
Notifications
You must be signed in to change notification settings - Fork 407
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[builtin Map] Map.prototype.entries method and map iterator (#847)
* Initial commit * Improving on Map iterator * Improvements on the iterator * Almost finish the next method of MapIterator * Add different kinds to next * fmt * Add function description. Add test. * Added symbol_iterator method. Refactor to use exactly the same function as "entries". Added test for it, unignored pending test. * Remove TODOs
- Loading branch information
Showing
8 changed files
with
294 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
use crate::{ | ||
builtins::{function::make_builtin_fn, iterable::create_iter_result_object, Array, Value}, | ||
object::ObjectData, | ||
property::{Attribute, DataDescriptor}, | ||
BoaProfiler, Context, Result, | ||
}; | ||
use gc::{Finalize, Trace}; | ||
|
||
#[derive(Debug, Clone, Finalize, Trace)] | ||
pub enum MapIterationKind { | ||
Key, | ||
Value, | ||
KeyAndValue, | ||
} | ||
|
||
/// The Map Iterator object represents an iteration over a map. It implements the iterator protocol. | ||
/// | ||
/// More information: | ||
/// - [ECMAScript reference][spec] | ||
/// | ||
/// [spec]: TODO https://tc39.es/ecma262/#sec-array-iterator-objects | ||
#[derive(Debug, Clone, Finalize, Trace)] | ||
pub struct MapIterator { | ||
iterated_map: Value, | ||
map_next_index: usize, | ||
map_iteration_kind: MapIterationKind, | ||
} | ||
|
||
impl MapIterator { | ||
pub(crate) const NAME: &'static str = "MapIterator"; | ||
|
||
fn new(map: Value, kind: MapIterationKind) -> Self { | ||
MapIterator { | ||
iterated_map: map, | ||
map_next_index: 0, | ||
map_iteration_kind: kind, | ||
} | ||
} | ||
|
||
/// Abstract operation CreateMapIterator( map, kind ) | ||
/// | ||
/// Creates a new iterator over the given map. | ||
/// | ||
/// More information: | ||
/// - [ECMA reference][spec] | ||
/// | ||
/// [spec]: https://www.ecma-international.org/ecma-262/11.0/index.html#sec-createmapiterator | ||
pub(crate) fn create_map_iterator( | ||
ctx: &Context, | ||
map: Value, | ||
kind: MapIterationKind, | ||
) -> Result<Value> { | ||
let map_iterator = Value::new_object(Some(ctx.global_object())); | ||
map_iterator.set_data(ObjectData::MapIterator(Self::new(map, kind))); | ||
map_iterator | ||
.as_object_mut() | ||
.expect("map iterator object") | ||
.set_prototype_instance(ctx.iterator_prototypes().map_iterator().into()); | ||
Ok(map_iterator) | ||
} | ||
|
||
/// %MapIteratorPrototype%.next( ) | ||
/// | ||
/// Advances the iterator and gets the next result in the map. | ||
/// | ||
/// More information: | ||
/// - [ECMA reference][spec] | ||
/// | ||
/// [spec]: https://tc39.es/ecma262/#sec-%mapiteratorprototype%.next | ||
pub(crate) fn next(this: &Value, _args: &[Value], ctx: &mut Context) -> Result<Value> { | ||
if let Value::Object(ref object) = this { | ||
let mut object = object.borrow_mut(); | ||
if let Some(map_iterator) = object.as_map_iterator_mut() { | ||
let m = &map_iterator.iterated_map; | ||
let mut index = map_iterator.map_next_index; | ||
let item_kind = &map_iterator.map_iteration_kind; | ||
|
||
if map_iterator.iterated_map.is_undefined() { | ||
return Ok(create_iter_result_object(ctx, Value::undefined(), true)); | ||
} | ||
|
||
if let Value::Object(ref object) = m { | ||
if let Some(entries) = object.borrow().as_map_ref() { | ||
let num_entries = entries.len(); | ||
while index < num_entries { | ||
let e = entries.get_index(index); | ||
index += 1; | ||
map_iterator.map_next_index = index; | ||
if let Some((key, value)) = e { | ||
match item_kind { | ||
MapIterationKind::Key => { | ||
return Ok(create_iter_result_object( | ||
ctx, | ||
key.clone(), | ||
false, | ||
)); | ||
} | ||
MapIterationKind::Value => { | ||
return Ok(create_iter_result_object( | ||
ctx, | ||
value.clone(), | ||
false, | ||
)); | ||
} | ||
MapIterationKind::KeyAndValue => { | ||
let result = Array::construct_array( | ||
&Array::new_array(ctx)?, | ||
&[key.clone(), value.clone()], | ||
)?; | ||
return Ok(create_iter_result_object(ctx, result, false)); | ||
} | ||
} | ||
} | ||
} | ||
} else { | ||
return Err(ctx.construct_type_error("'this' is not a Map")); | ||
} | ||
} else { | ||
return Err(ctx.construct_type_error("'this' is not a Map")); | ||
} | ||
|
||
map_iterator.iterated_map = Value::undefined(); | ||
Ok(create_iter_result_object(ctx, Value::undefined(), true)) | ||
} else { | ||
ctx.throw_type_error("`this` is not an MapIterator") | ||
} | ||
} else { | ||
ctx.throw_type_error("`this` is not an MapIterator") | ||
} | ||
} | ||
|
||
/// Create the %MapIteratorPrototype% object | ||
/// | ||
/// More information: | ||
/// - [ECMA reference][spec] | ||
/// | ||
/// [spec]: https://tc39.es/ecma262/#sec-%mapiteratorprototype%-object | ||
pub(crate) fn create_prototype(ctx: &mut Context, iterator_prototype: Value) -> Value { | ||
let global = ctx.global_object(); | ||
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); | ||
|
||
// Create prototype | ||
let map_iterator = Value::new_object(Some(global)); | ||
make_builtin_fn(Self::next, "next", &map_iterator, 0, ctx); | ||
map_iterator | ||
.as_object_mut() | ||
.expect("map iterator prototype object") | ||
.set_prototype_instance(iterator_prototype); | ||
|
||
let to_string_tag = ctx.well_known_symbols().to_string_tag_symbol(); | ||
let to_string_tag_property = DataDescriptor::new("Map Iterator", Attribute::CONFIGURABLE); | ||
map_iterator.set_property(to_string_tag, to_string_tag_property); | ||
map_iterator | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.