mirror of https://github.com/boa-dev/boa.git
Browse Source
* 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 TODOspull/878/head
croraf
4 years ago
committed by
GitHub
8 changed files with 294 additions and 4 deletions
@ -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 |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue