Skip to content

Commit

Permalink
Started with Typed Arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
Razican committed Sep 8, 2021
1 parent c91af15 commit f7cff7c
Show file tree
Hide file tree
Showing 23 changed files with 898 additions and 185 deletions.
7 changes: 2 additions & 5 deletions boa/src/builtins/date/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1713,11 +1713,8 @@ impl Date {
}

// 4. Return ? Invoke(O, "toISOString").
if let Some(to_iso_string) = o.get_method(context, "toISOString")? {
to_iso_string.call(this, &[], context)
} else {
context.throw_type_error("toISOString in undefined")
}
let func = o.get("toISOString", context)?;
o.call(&func, &[], context)
}

/// `Date.prototype.toString()`
Expand Down
119 changes: 107 additions & 12 deletions boa/src/builtins/iterable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl IteratorPrototypes {
}
}

/// CreateIterResultObject( value, done )
/// `CreateIterResultObject( value, done )`
///
/// Generates an object supporting the IteratorResult interface.
pub fn create_iter_result_object(context: &mut Context, value: JsValue, done: bool) -> JsValue {
Expand All @@ -100,18 +100,70 @@ pub fn create_iter_result_object(context: &mut Context, value: JsValue, done: bo
obj.into()
}

/// Get an iterator record
pub fn get_iterator(context: &mut Context, iterable: JsValue) -> JsResult<IteratorRecord> {
let iterator_function = iterable.get_field(WellKnownSymbols::iterator(), context)?;
if iterator_function.is_null_or_undefined() {
return Err(context.construct_type_error("Not an iterable"));
}
let iterator_object = context.call(&iterator_function, &iterable, &[])?;
let next_function = iterator_object.get_field("next", context)?;
if next_function.is_null_or_undefined() {
return Err(context.construct_type_error("Could not find property `next`"));
/// Iterator hint for `GetIterator`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IteratorHint {
Sync,
Async,
}

impl JsValue {
/// `GetIterator ( obj [ , hint [ , method ] ] )`
///
/// More information:
/// - [ECMA reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-getiterator
pub fn get_iterator(
self,
context: &mut Context,
hint: Option<IteratorHint>,
method: Option<JsValue>,
) -> JsResult<IteratorRecord> {
// 1. If hint is not present, set hint to sync.
let hint = hint.unwrap_or(IteratorHint::Sync);

// 2. If method is not present, then
let method = if let Some(method) = method {
method
} else {
// a. If hint is async, then
if hint == IteratorHint::Async {
// i. Set method to ? GetMethod(obj, @@asyncIterator).
let method = self.get_method(context, WellKnownSymbols::async_iterator())?;
// ii. If method is undefined, then
if method.is_undefined() {
// 1. Let syncMethod be ? GetMethod(obj, @@iterator).
let sync_method = self.get_method(context, WellKnownSymbols::iterator())?;
// 2. Let syncIteratorRecord be ? GetIterator(obj, sync, syncMethod).
let sync_iterator_record =
self.get_iterator(context, Some(IteratorHint::Sync), Some(sync_method));
// 3. Return ! CreateAsyncFromSyncIterator(syncIteratorRecord).
todo!("CreateAsyncFromSyncIterator");
}

method
} else {
// b. Otherwise, set method to ? GetMethod(obj, @@iterator).
self.get_method(context, WellKnownSymbols::iterator())?
}
};

// 3. Let iterator be ? Call(method, obj).
let iterator = context.call(&method, &self, &[])?;

// 4. If Type(iterator) is not Object, throw a TypeError exception.
if !iterator.is_object() {
return Err(context.construct_type_error("the iterator is not an object"));
}

// 5. Let nextMethod be ? GetV(iterator, "next").
let next_method = iterator.get_v(context, "next")?;

// 6. Let iteratorRecord be the Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
// 7. Return iteratorRecord.
Ok(IteratorRecord::new(iterator, next_method))
}
Ok(IteratorRecord::new(iterator_object, next_function))
}

/// Create the %IteratorPrototype% object
Expand Down Expand Up @@ -201,6 +253,49 @@ impl IteratorRecord {
}
}

/// `IterableToList ( items [ , method ] )`
///
/// More information:
/// - [ECMA reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-iterabletolist
pub(crate) fn iterable_to_list(
context: &mut Context,
items: JsValue,
method: Option<JsValue>,
) -> JsResult<Vec<JsValue>> {
// 1. If method is present, then
let iterator_record = if let Some(method) = method {
// a. Let iteratorRecord be ? GetIterator(items, sync, method).
items.get_iterator(context, Some(IteratorHint::Sync), Some(method))?
} else {
// 2. Else,

// a. Let iteratorRecord be ? GetIterator(items, sync).
items.get_iterator(context, Some(IteratorHint::Sync), None)?
};
// 3. Let values be a new empty List.
let mut values = Vec::new();

// 4. Let next be true.
// 5. Repeat, while next is not false,
// a. Set next to ? IteratorStep(iteratorRecord).
// b. If next is not false, then
// i. Let nextValue be ? IteratorValue(next).
// ii. Append nextValue to the end of the List values.
loop {
let next = iterator_record.next(context)?;
if next.is_done() {
break;
}

values.push(next.value())
}

// 6. Return values.
Ok(values)
}

#[derive(Debug)]
pub struct IteratorResult {
value: JsValue,
Expand Down
16 changes: 16 additions & 0 deletions boa/src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod regexp;
pub mod set;
pub mod string;
pub mod symbol;
pub mod typed_array;
pub mod undefined;

pub(crate) use self::{
Expand All @@ -50,6 +51,10 @@ pub(crate) use self::{
set::Set,
string::String,
symbol::Symbol,
typed_array::{
BigInt64Array, BigUint64Array, Float32Array, Float64Array, Int16Array, Int32Array,
Int8Array, Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray,
},
undefined::Undefined,
};
use crate::{
Expand Down Expand Up @@ -87,6 +92,17 @@ pub fn init(context: &mut Context) {
Set::init,
String::init,
RegExp::init,
Int8Array::init,
Uint8Array::init,
Uint8ClampedArray::init,
Int16Array::init,
Uint16Array::init,
Int32Array::init,
Uint32Array::init,
BigInt64Array::init,
BigUint64Array::init,
Float32Array::init,
Float64Array::init,
Symbol::init,
Error::init,
RangeError::init,
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/regexp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,7 @@ impl RegExp {
let named_groups = match_value.named_groups();
let groups = if named_groups.clone().count() > 0 {
// a. Let groups be ! OrdinaryObjectCreate(null).
let groups = JsValue::new_object(context);
let groups = JsValue::from(JsObject::new(Object::create(JsValue::null())));

// Perform 27.f here
// f. If the ith capture of R was defined with a GroupName, then
Expand Down
4 changes: 2 additions & 2 deletions boa/src/builtins/set/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

use crate::{
builtins::{iterable::get_iterator, BuiltIn},
builtins::BuiltIn,
context::StandardObjects,
object::{
internal_methods::get_prototype_from_constructor, ConstructorBuilder, FunctionBuilder,
Expand Down Expand Up @@ -152,7 +152,7 @@ impl Set {
}

// 7
let iterator_record = get_iterator(context, iterable.clone())?;
let iterator_record = iterable.clone().get_iterator(context, None, None)?;

// 8.a
let mut next = iterator_record.next(context)?;
Expand Down
76 changes: 27 additions & 49 deletions boa/src/builtins/string/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,16 +728,13 @@ impl String {
// 2. If searchValue is neither undefined nor null, then
if !search_value.is_null_or_undefined() {
// a. Let replacer be ? GetMethod(searchValue, @@replace).
let replacer = search_value
.as_object()
.unwrap_or_default()
.get_method(context, WellKnownSymbols::replace())?;
let replacer = search_value.get_method(context, WellKnownSymbols::replace())?;

// b. If replacer is not undefined, then
if let Some(replacer) = replacer {
if !replacer.is_undefined() {
// i. Return ? Call(replacer, searchValue, « O, replaceValue »).
return context.call(
&replacer.into(),
&replacer,
search_value,
&[this.clone(), replace_value.clone()],
);
Expand Down Expand Up @@ -862,15 +859,12 @@ impl String {
}

// c. Let replacer be ? GetMethod(searchValue, @@replace).
let replacer = search_value
.as_object()
.unwrap_or_default()
.get_method(context, WellKnownSymbols::replace())?;
let replacer = search_value.get_method(context, WellKnownSymbols::replace())?;

// d. If replacer is not undefined, then
if let Some(replacer) = replacer {
if !replacer.is_undefined() {
// i. Return ? Call(replacer, searchValue, « O, replaceValue »).
return replacer.call(search_value, &[o.into(), replace_value.clone()], context);
return context.call(&replacer, search_value, &[o.into(), replace_value.clone()]);
}
}

Expand Down Expand Up @@ -1103,12 +1097,11 @@ impl String {
let regexp = args.get_or_undefined(0);
if !regexp.is_null_or_undefined() {
// a. Let matcher be ? GetMethod(regexp, @@match).
let matcher = regexp.get_method(context, WellKnownSymbols::match_())?;
// b. If matcher is not undefined, then
if let Some(obj) = regexp.as_object() {
if let Some(matcher) = obj.get_method(context, WellKnownSymbols::match_())? {
// i. Return ? Call(matcher, regexp, « O »).
return matcher.call(regexp, &[o.clone()], context);
}
if !matcher.is_undefined() {
// i. Return ? Call(matcher, regexp, « O »).
return context.call(&matcher, regexp, &[o.clone()]);
}
}

Expand All @@ -1120,11 +1113,8 @@ impl String {

// 5. Return ? Invoke(rx, @@match, « S »).
let obj = rx.as_object().expect("RegExpCreate must return Object");
if let Some(matcher) = obj.get_method(context, WellKnownSymbols::match_())? {
matcher.call(&rx, &[JsValue::new(s)], context)
} else {
context.throw_type_error("RegExp[Symbol.match] is undefined")
}
let func = obj.get(WellKnownSymbols::match_(), context)?;
obj.call(&func, &[JsValue::new(s)], context)
}

/// Abstract method `StringPad`.
Expand Down Expand Up @@ -1474,14 +1464,11 @@ impl String {
// 2. If separator is neither undefined nor null, then
if !separator.is_null_or_undefined() {
// a. Let splitter be ? GetMethod(separator, @@split).
let splitter = separator.get_method(context, WellKnownSymbols::split())?;
// b. If splitter is not undefined, then
if let Some(splitter) = separator
.as_object()
.unwrap_or_default()
.get_method(context, WellKnownSymbols::split())?
{
if !splitter.is_undefined() {
// i. Return ? Call(splitter, separator, « O, limit »).
return splitter.call(separator, &[this.clone(), limit.clone()], context);
return context.call(&splitter, separator, &[this.clone(), limit.clone()]);
}
}

Expand Down Expand Up @@ -1664,12 +1651,11 @@ impl String {
}

// c. Let matcher be ? GetMethod(regexp, @@matchAll).
let matcher = regexp.get_method(context, WellKnownSymbols::match_all())?;
// d. If matcher is not undefined, then
if let Some(obj) = regexp.as_object() {
if let Some(matcher) = obj.get_method(context, WellKnownSymbols::match_all())? {
// i. Return ? Call(matcher, regexp, « O »).
return matcher.call(regexp, &[o.clone()], context);
}
if !matcher.is_undefined() {
// i. Return ? Call(matcher, regexp, « O »).
return context.call(&matcher, regexp, &[o.clone()]);
}
}

Expand All @@ -1681,11 +1667,8 @@ impl String {

// 5. Return ? Invoke(rx, @@matchAll, « S »).
let obj = rx.as_object().expect("RegExpCreate must return Object");
if let Some(matcher) = obj.get_method(context, WellKnownSymbols::match_all())? {
matcher.call(&rx, &[JsValue::new(s)], context)
} else {
context.throw_type_error("RegExp[Symbol.matchAll] is undefined")
}
let func = obj.get(WellKnownSymbols::match_all(), context)?;
obj.call(&func, &[JsValue::new(s)], context)
}

/// `String.prototype.normalize( [ form ] )`
Expand Down Expand Up @@ -1748,12 +1731,11 @@ impl String {
let regexp = args.get_or_undefined(0);
if !regexp.is_null_or_undefined() {
// a. Let searcher be ? GetMethod(regexp, @@search).
let searcher = regexp.get_method(context, WellKnownSymbols::search())?;
// b. If searcher is not undefined, then
if let Some(obj) = regexp.as_object() {
if let Some(searcher) = obj.get_method(context, WellKnownSymbols::search())? {
// i. Return ? Call(searcher, regexp, « O »).
return searcher.call(regexp, &[o.clone()], context);
}
if !searcher.is_undefined() {
// i. Return ? Call(searcher, regexp, « O »).
return context.call(&searcher, regexp, &[o.clone()]);
}
}

Expand All @@ -1764,12 +1746,8 @@ impl String {
let rx = RegExp::create(regexp.clone(), JsValue::undefined(), context)?;

// 5. Return ? Invoke(rx, @@search, « string »).
let obj = rx.as_object().expect("RegExpCreate must return Object");
if let Some(matcher) = obj.get_method(context, WellKnownSymbols::search())? {
matcher.call(&rx, &[JsValue::new(string)], context)
} else {
context.throw_type_error("RegExp[Symbol.search] is undefined")
}
let func = rx.get_v(context, WellKnownSymbols::search())?;
context.call(&func, &rx, &[JsValue::new(string)])
}

pub(crate) fn iterator(
Expand Down

0 comments on commit f7cff7c

Please sign in to comment.