Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of for...of loops #704

Merged
merged 39 commits into from
Oct 2, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
27f92ed
Initial implementation of for...of loop
joshwd36 Sep 17, 2020
39adfef
Initial implementation of for...of loop
joshwd36 Sep 17, 2020
c3e388f
Extend for...of to support var, let, and const lhs
joshwd36 Sep 23, 2020
fc2d560
Use cached well known symbols
joshwd36 Sep 23, 2020
fcb4869
Merge remote-tracking branch 'origin/Iterables' into Iterables
joshwd36 Sep 23, 2020
21a1c02
Nest use statements
joshwd36 Sep 23, 2020
3536085
Nest use statements
joshwd36 Sep 23, 2020
b428960
Add tests.
joshwd36 Sep 23, 2020
6659087
Initial implementation of for...of loop
joshwd36 Sep 17, 2020
3d1d398
Extend for...of to support var, let, and const lhs
joshwd36 Sep 23, 2020
6209208
Use cached well known symbols
joshwd36 Sep 23, 2020
f32f090
Nest use statements
joshwd36 Sep 23, 2020
08d4a93
Nest use statements
joshwd36 Sep 23, 2020
a6afab7
Add tests.
joshwd36 Sep 23, 2020
e1ba773
Add tests, cache iterator prototypes, pull common iterator functions …
joshwd36 Sep 25, 2020
9ce630e
Merge remote-tracking branch 'origin/Iterables' into Iterables
joshwd36 Sep 25, 2020
66f4c79
Initial implementation of for...of loop
joshwd36 Sep 17, 2020
5228e56
Extend for...of to support var, let, and const lhs
joshwd36 Sep 23, 2020
b49e03f
Use cached well known symbols
joshwd36 Sep 23, 2020
1db94ab
Nest use statements
joshwd36 Sep 23, 2020
3737ca7
Nest use statements
joshwd36 Sep 23, 2020
f1d3639
Add tests.
joshwd36 Sep 23, 2020
a6e0dd2
Add tests, cache iterator prototypes, pull common iterator functions …
joshwd36 Sep 25, 2020
6287bb2
Initial implementation of for...of loop
joshwd36 Sep 17, 2020
2ca4003
Extend for...of to support var, let, and const lhs
joshwd36 Sep 23, 2020
42a0741
Use cached well known symbols
joshwd36 Sep 23, 2020
57a67b2
Initial implementation of for...of loop
joshwd36 Sep 17, 2020
a451f4b
Nest use statements
joshwd36 Sep 23, 2020
8f80692
Add string iterator
joshwd36 Sep 29, 2020
384c824
Clean up merge
joshwd36 Sep 29, 2020
08a6f51
Merge remote-tracking branch 'origin/Iterables' into Iterables
joshwd36 Sep 29, 2020
29e1dee
Use ctx.global_iterator()
joshwd36 Oct 2, 2020
7e565e8
Merge remote-tracking branch 'upstream/master' into Iterables
joshwd36 Oct 2, 2020
8e91a22
Merge upstream
joshwd36 Oct 2, 2020
0abe3c7
Use u32 as array next index
joshwd36 Oct 2, 2020
9b43518
Use into
joshwd36 Oct 2, 2020
3a5d75f
Use boa::Result
joshwd36 Oct 2, 2020
69c76c4
Tidy up use statement
joshwd36 Oct 2, 2020
875a383
Tidy up use statement
joshwd36 Oct 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions boa/src/builtins/array/array_iterator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
use crate::{
builtins::{
function::{make_builtin_fn, BuiltInFunction, Function, FunctionFlags},
Array, Value,
},
object::{Object, ObjectData, PROTOTYPE},
property::Property,
Context, Result,
};
use gc::{Finalize, Trace};
use std::borrow::Borrow;

#[derive(Debug, Clone, Finalize, Trace)]
pub enum ArrayIterationKind {
Key,
Value,
KeyAndValue,
}

#[derive(Debug, Clone, Finalize, Trace)]
pub struct ArrayIterator {
array: Value,
next_index: i32,
joshwd36 marked this conversation as resolved.
Show resolved Hide resolved
kind: ArrayIterationKind,
}

impl ArrayIterator {
fn new(array: Value, kind: ArrayIterationKind) -> Self {
ArrayIterator {
array,
kind,
next_index: 0,
}
}

pub(crate) fn new_array_iterator(
ctx: &Context,
array: Value,
kind: ArrayIterationKind,
) -> Result<Value> {
let array_iterator = Value::new_object(Some(
&ctx.realm()
.environment
.get_global_object()
.expect("Could not get global object"),
joshwd36 marked this conversation as resolved.
Show resolved Hide resolved
));
array_iterator.set_data(ObjectData::ArrayIterator(Self::new(array, kind)));
array_iterator
.as_object_mut()
.expect("array iterator object")
.set_prototype_instance(
ctx.realm()
.environment
.get_binding_value("Object")
.expect("Object was not initialized")
.borrow()
.get_field(PROTOTYPE),
);
make_builtin_fn(Self::next, "next", &array_iterator, 0, ctx);
let mut function = Object::function(
Function::BuiltIn(
BuiltInFunction(|v, _, _| Ok(v.clone())),
FunctionFlags::CALLABLE,
),
ctx.global_object()
.get_field("Function")
.get_field("prototype"),
);
joshwd36 marked this conversation as resolved.
Show resolved Hide resolved
function.insert_field("length", Value::from(0));

let symbol_iterator = ctx.well_known_symbols().iterator_symbol();
array_iterator.set_field(symbol_iterator, Value::from(function));
Ok(array_iterator)
}

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(array_iterator) = object.as_array_iterator_mut() {
let index = array_iterator.next_index;
if array_iterator.array.is_undefined() {
return Ok(Self::create_iter_result_object(
ctx,
Value::undefined(),
true,
));
}
let len = array_iterator
.array
.get_field("length")
.as_number()
.ok_or_else(|| ctx.construct_type_error("Not an array"))?
as i32;
if array_iterator.next_index >= len {
array_iterator.array = Value::undefined();
return Ok(Self::create_iter_result_object(
ctx,
Value::undefined(),
true,
));
}
array_iterator.next_index = index + 1;
match array_iterator.kind {
ArrayIterationKind::Key => Ok(Self::create_iter_result_object(
ctx,
Value::integer(index),
false,
)),
ArrayIterationKind::Value => {
let element_value = array_iterator.array.get_field(index);
Ok(Self::create_iter_result_object(ctx, element_value, false))
}
ArrayIterationKind::KeyAndValue => {
let element_value = array_iterator.array.get_field(index);
let result = Array::make_array(
&Value::new_object(Some(
&ctx.realm()
.environment
.get_global_object()
.expect("Could not get global object"),
joshwd36 marked this conversation as resolved.
Show resolved Hide resolved
)),
&[Value::integer(index), element_value],
ctx,
)?;
Ok(result)
}
}
} else {
ctx.throw_type_error("`this` is not an ArrayIterator")
}
} else {
ctx.throw_type_error("`this` is not an ArrayIterator")
}
}

fn create_iter_result_object(ctx: &mut Context, value: Value, done: bool) -> Value {
let object = Value::new_object(Some(
&ctx.realm()
.environment
.get_global_object()
.expect("Could not get global object"),
));
let value_property = Property::default().value(value);
let done_property = Property::default().value(Value::boolean(done));
object.set_property("value", value_property);
object.set_property("done", done_property);
object
}
}
17 changes: 17 additions & 0 deletions boa/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
//! [spec]: https://tc39.es/ecma262/#sec-array-objects
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

pub mod array_iterator;
#[cfg(test)]
mod tests;

use super::function::{make_builtin_fn, make_constructor_fn};
use crate::{
builtins::array::array_iterator::{ArrayIterationKind, ArrayIterator},
object::{ObjectData, PROTOTYPE},
property::{Attribute, Property},
value::{same_value_zero, Value},
Expand Down Expand Up @@ -1091,6 +1093,14 @@ impl Array {
Ok(accumulator)
}

pub(crate) fn values(
this: &Value,
_args: &[Value],
interpreter: &mut Context,
) -> Result<Value> {
ArrayIterator::new_array_iterator(interpreter, this.clone(), ArrayIterationKind::Value)
}

/// Initialise the `Array` object on the global object.
#[inline]
pub(crate) fn init(interpreter: &mut Context) -> (&'static str, Value) {
Expand Down Expand Up @@ -1137,6 +1147,13 @@ impl Array {
2,
interpreter,
);
make_builtin_fn(Self::values, "values", &prototype, 0, interpreter);

let symbol_iterator = interpreter.well_known_symbols().iterator_symbol();
prototype.set_property(
symbol_iterator,
Property::default().value(prototype.get_field("values")),
);

let array = make_constructor_fn(
Self::NAME,
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub fn init(interpreter: &mut Context) {
// The `Function` global must be initialized before other types.
function::init,
Object::init,
Symbol::init,
Array::init,
BigInt::init,
Boolean::init,
Expand All @@ -59,7 +60,6 @@ pub fn init(interpreter: &mut Context) {
Number::init,
RegExp::init,
String::init,
Symbol::init,
Console::init,
// Global error types.
Error::init,
Expand Down
6 changes: 5 additions & 1 deletion boa/src/exec/declaration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ impl Executable for VarDeclList {
impl Executable for ConstDeclList {
fn run(&self, interpreter: &mut Context) -> Result<Value> {
for decl in self.as_ref() {
let val = decl.init().run(interpreter)?;
let val = if let Some(init) = decl.init() {
init.run(interpreter)?
} else {
return interpreter.throw_syntax_error("missing = in const declaration");
};

interpreter
.realm_mut()
Expand Down
Loading