-
-
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.
* Implement for..in * Fix code styling issue * Add break and continue with label * Add break and continue for while and do-while * Add unit tests * Fix formatting * Split node ForInOfLoop into ForInLoop and ForOfLoop * Fix issues in ForInOfLoop node splitting * Merge with master branch Co-authored-by: tofpie <tofpie@users.noreply.github.com>
- Loading branch information
Showing
16 changed files
with
678 additions
and
82 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,145 @@ | ||
use crate::property::PropertyKey; | ||
use crate::value::RcString; | ||
use crate::{ | ||
builtins::{function::make_builtin_fn, iterable::create_iter_result_object}, | ||
gc::{Finalize, Trace}, | ||
object::ObjectData, | ||
property::{Attribute, DataDescriptor}, | ||
BoaProfiler, Context, Result, Value, | ||
}; | ||
use rustc_hash::FxHashSet; | ||
use std::collections::VecDeque; | ||
|
||
/// The ForInIterator object represents an iteration over some specific object. | ||
/// It implements the iterator protocol. | ||
/// | ||
/// More information: | ||
/// - [ECMAScript reference][spec] | ||
/// | ||
/// [spec]: https://tc39.es/ecma262/#sec-for-in-iterator-objects | ||
#[derive(Debug, Clone, Finalize, Trace)] | ||
pub struct ForInIterator { | ||
object: Value, | ||
visited_keys: FxHashSet<RcString>, | ||
remaining_keys: VecDeque<RcString>, | ||
object_was_visited: bool, | ||
} | ||
|
||
impl ForInIterator { | ||
pub(crate) const NAME: &'static str = "ForInIterator"; | ||
|
||
fn new(object: Value) -> Self { | ||
ForInIterator { | ||
object, | ||
visited_keys: FxHashSet::default(), | ||
remaining_keys: VecDeque::default(), | ||
object_was_visited: false, | ||
} | ||
} | ||
|
||
/// CreateForInIterator( object ) | ||
/// | ||
/// Creates a new iterator over the given object. | ||
/// | ||
/// More information: | ||
/// - [ECMA reference][spec] | ||
/// | ||
/// [spec]: https://tc39.es/ecma262/#sec-createforiniterator | ||
pub(crate) fn create_for_in_iterator(context: &Context, object: Value) -> Result<Value> { | ||
let for_in_iterator = Value::new_object(context); | ||
for_in_iterator.set_data(ObjectData::ForInIterator(Self::new(object))); | ||
for_in_iterator | ||
.as_object() | ||
.expect("for in iterator object") | ||
.set_prototype_instance(context.iterator_prototypes().for_in_iterator().into()); | ||
Ok(for_in_iterator) | ||
} | ||
|
||
/// %ForInIteratorPrototype%.next( ) | ||
/// | ||
/// Gets the next result in the object. | ||
/// | ||
/// More information: | ||
/// - [ECMA reference][spec] | ||
/// | ||
/// [spec]: https://tc39.es/ecma262/#sec-%foriniteratorprototype%.next | ||
pub(crate) fn next(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> { | ||
if let Value::Object(ref o) = this { | ||
let mut for_in_iterator = o.borrow_mut(); | ||
if let Some(iterator) = for_in_iterator.as_for_in_iterator_mut() { | ||
let mut object = iterator.object.to_object(context)?; | ||
loop { | ||
if !iterator.object_was_visited { | ||
let keys = object.own_property_keys(); | ||
for k in keys { | ||
match k { | ||
PropertyKey::String(ref k) => { | ||
iterator.remaining_keys.push_back(k.clone()); | ||
} | ||
PropertyKey::Index(i) => { | ||
iterator.remaining_keys.push_back(i.to_string().into()); | ||
} | ||
_ => {} | ||
} | ||
} | ||
iterator.object_was_visited = true; | ||
} | ||
while let Some(r) = iterator.remaining_keys.pop_front() { | ||
if !iterator.visited_keys.contains(&r) { | ||
if let Some(desc) = | ||
object.get_own_property(&PropertyKey::from(r.clone())) | ||
{ | ||
iterator.visited_keys.insert(r.clone()); | ||
if desc.enumerable() { | ||
return Ok(create_iter_result_object( | ||
context, | ||
Value::from(r.to_string()), | ||
false, | ||
)); | ||
} | ||
} | ||
} | ||
} | ||
match object.prototype_instance().to_object(context) { | ||
Ok(o) => { | ||
object = o; | ||
} | ||
_ => { | ||
return Ok(create_iter_result_object(context, Value::undefined(), true)) | ||
} | ||
} | ||
iterator.object = Value::from(object.clone()); | ||
iterator.object_was_visited = false; | ||
} | ||
} else { | ||
context.throw_type_error("`this` is not a ForInIterator") | ||
} | ||
} else { | ||
context.throw_type_error("`this` is not an ForInIterator") | ||
} | ||
} | ||
|
||
/// Create the %ArrayIteratorPrototype% object | ||
/// | ||
/// More information: | ||
/// - [ECMA reference][spec] | ||
/// | ||
/// [spec]: https://tc39.es/ecma262/#sec-%foriniteratorprototype%-object | ||
pub(crate) fn create_prototype(context: &mut Context, iterator_prototype: Value) -> Value { | ||
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); | ||
|
||
// Create prototype | ||
let for_in_iterator = Value::new_object(context); | ||
make_builtin_fn(Self::next, "next", &for_in_iterator, 0, context); | ||
for_in_iterator | ||
.as_object() | ||
.expect("for in iterator prototype object") | ||
.set_prototype_instance(iterator_prototype); | ||
|
||
let to_string_tag = context.well_known_symbols().to_string_tag_symbol(); | ||
let to_string_tag_property = | ||
DataDescriptor::new("For In Iterator", Attribute::CONFIGURABLE); | ||
for_in_iterator.set_property(to_string_tag, to_string_tag_property); | ||
for_in_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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ use crate::{ | |
BoaProfiler, Context, Result, | ||
}; | ||
|
||
pub mod for_in_iterator; | ||
#[cfg(test)] | ||
mod tests; | ||
|
||
|
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.