Skip to content

Commit

Permalink
Refactor Function internal methods and implement BoundFunction ob…
Browse files Browse the repository at this point in the history
…jects (#1583)

* Refactor `[[Call]]` and `[[Construct]]` to be InternalFunctions

* Implement `BoundFunction` exotic objects

* Implement remaining `Function` builtin methods

* Lift `OrdinaryHasInstance` to be inside JsValue

* Implement `JsValue::InstanceOf` operator inside JsValue

* Implement `JsValue::[as/is]_[callable/constructor]

* Enable mutability for the `Closure` type inside closures
  • Loading branch information
jedel1043 authored Oct 11, 2021
1 parent bec891a commit 9f84546
Show file tree
Hide file tree
Showing 44 changed files with 1,733 additions and 1,428 deletions.
15 changes: 13 additions & 2 deletions boa/examples/closures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ fn main() -> Result<(), JsValue> {
println!("Called `closure`");
// `variable` is captured from the main function.
println!("variable = {}", variable);
println!();

// We return the moved variable as a `JsValue`.
Ok(JsValue::new(variable))
Expand Down Expand Up @@ -52,7 +53,7 @@ fn main() -> Result<(), JsValue> {

// Now, we execute some operations that return a `Clone` type
let clone_variable = BigStruct {
greeting: JsString::from("Hello from Javascript!"),
greeting: JsString::from("Hello!"),
object,
};

Expand All @@ -73,7 +74,11 @@ fn main() -> Result<(), JsValue> {
captures.greeting.as_str(),
]);

// We can also mutate the moved data inside the closure.
captures.greeting = format!("{} Hello!", captures.greeting).into();

println!("{}", message);
println!();

// We convert `message` into `Jsvalue` to be able to return it.
Ok(message.into())
Expand All @@ -100,7 +105,13 @@ fn main() -> Result<(), JsValue> {

assert_eq!(
context.eval("createMessage()")?,
"message from `Boa dev`: Hello from Javascript!".into()
"message from `Boa dev`: Hello!".into()
);

// The data mutates between calls
assert_eq!(
context.eval("createMessage(); createMessage();")?,
"message from `Boa dev`: Hello! Hello! Hello!".into()
);

// We have moved `Clone` variables into a closure and executed that closure
Expand Down
88 changes: 42 additions & 46 deletions boa/src/builtins/array/array_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,57 +62,53 @@ impl ArrayIterator {
///
/// [spec]: https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
pub(crate) fn next(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
if let JsValue::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.done {
return Ok(create_iter_result_object(
JsValue::undefined(),
true,
context,
));
}
let mut array_iterator = this.as_object().map(|obj| obj.borrow_mut());
let array_iterator = array_iterator
.as_mut()
.and_then(|obj| obj.as_array_iterator_mut())
.ok_or_else(|| context.construct_type_error("`this` is not an ArrayIterator"))?;
let index = array_iterator.next_index;
if array_iterator.done {
return Ok(create_iter_result_object(
JsValue::undefined(),
true,
context,
));
}

let len = if let Some(f) = array_iterator.array.borrow().as_typed_array() {
if f.is_detached() {
return context.throw_type_error(
"Cannot get value from typed array that has a detached array buffer",
);
}
let len = if let Some(f) = array_iterator.array.borrow().as_typed_array() {
if f.is_detached() {
return context.throw_type_error(
"Cannot get value from typed array that has a detached array buffer",
);
}

f.array_length()
} else {
array_iterator.array.length_of_array_like(context)?
};
f.array_length()
} else {
array_iterator.array.length_of_array_like(context)?
};

if index >= len {
array_iterator.done = true;
return Ok(create_iter_result_object(
JsValue::undefined(),
true,
context,
));
}
array_iterator.next_index = index + 1;
return match array_iterator.kind {
PropertyNameKind::Key => {
Ok(create_iter_result_object(index.into(), false, context))
}
PropertyNameKind::Value => {
let element_value = array_iterator.array.get(index, context)?;
Ok(create_iter_result_object(element_value, false, context))
}
PropertyNameKind::KeyAndValue => {
let element_value = array_iterator.array.get(index, context)?;
let result =
Array::create_array_from_list([index.into(), element_value], context);
Ok(create_iter_result_object(result.into(), false, context))
}
};
if index >= len {
array_iterator.done = true;
return Ok(create_iter_result_object(
JsValue::undefined(),
true,
context,
));
}
array_iterator.next_index = index + 1;
match array_iterator.kind {
PropertyNameKind::Key => Ok(create_iter_result_object(index.into(), false, context)),
PropertyNameKind::Value => {
let element_value = array_iterator.array.get(index, context)?;
Ok(create_iter_result_object(element_value, false, context))
}
PropertyNameKind::KeyAndValue => {
let element_value = array_iterator.array.get(index, context)?;
let result = Array::create_array_from_list([index.into(), element_value], context);
Ok(create_iter_result_object(result.into(), false, context))
}
}
context.throw_type_error("`this` is not an ArrayIterator")
}

/// Create the %ArrayIteratorPrototype% object
Expand Down
Loading

0 comments on commit 9f84546

Please sign in to comment.