From c79e40a1dd42abc2aa00f66060588f2e3d9962a2 Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Tue, 30 May 2023 09:34:05 +1000 Subject: [PATCH] Add array.entries() --- .../src/iteration/array_entries_iterator.rs | 137 ++++++++++++++++++ valuescript_vm/src/iteration/mod.rs | 1 + .../src/iteration/string_iterator.rs | 4 +- valuescript_vm/src/string_methods.rs | 8 +- valuescript_vm/src/vs_array.rs | 17 +-- 5 files changed, 149 insertions(+), 18 deletions(-) create mode 100644 valuescript_vm/src/iteration/array_entries_iterator.rs diff --git a/valuescript_vm/src/iteration/array_entries_iterator.rs b/valuescript_vm/src/iteration/array_entries_iterator.rs new file mode 100644 index 0000000..1ea9127 --- /dev/null +++ b/valuescript_vm/src/iteration/array_entries_iterator.rs @@ -0,0 +1,137 @@ +use std::{fmt, rc::Rc}; + +use num_bigint::BigInt; + +use crate::{ + builtins::{error_builtin::ToError, type_error_builtin::ToTypeError}, + native_function::{native_fn, NativeFunction}, + vs_array::VsArray, + vs_class::VsClass, + vs_value::{dynamic_make_mut, ToDynamicVal, ToVal, Val, VsType}, + LoadFunctionResult, ValTrait, +}; + +use super::iteration_result::IterationResult; + +#[derive(Clone)] +pub struct ArrayEntriesIterator { + pub array: Rc, + pub index: usize, +} + +impl ArrayEntriesIterator { + pub fn new(array: Rc) -> ArrayEntriesIterator { + ArrayEntriesIterator { array, index: 0 } + } +} + +impl ValTrait for ArrayEntriesIterator { + fn typeof_(&self) -> VsType { + VsType::Object + } + + fn to_number(&self) -> f64 { + core::f64::NAN + } + + fn to_index(&self) -> Option { + None + } + + fn is_primitive(&self) -> bool { + false + } + + fn is_truthy(&self) -> bool { + true + } + + fn is_nullish(&self) -> bool { + false + } + + fn bind(&self, _params: Vec) -> Option { + None + } + + fn as_bigint_data(&self) -> Option { + None + } + + fn as_array_data(&self) -> Option> { + None + } + + fn as_class_data(&self) -> Option> { + None + } + + fn load_function(&self) -> LoadFunctionResult { + LoadFunctionResult::NotAFunction + } + + fn sub(&self, key: Val) -> Result { + if key.to_string() == "next" { + return Ok(NEXT.to_val()); + } + + Ok(Val::Undefined) + } + + fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> { + Err("Cannot assign to subscript of array iterator".to_type_error()) + } + + fn pretty_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "\x1b[36m[ArrayEntriesIterator]\x1b[39m") + } + + fn codify(&self) -> String { + format!( + "ArrayEntriesIterator({{ array: {}, index: {} }})", + Val::Array(self.array.clone()).codify(), + self.index + ) + } +} + +impl fmt::Display for ArrayEntriesIterator { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[object Array Iterator]") + } +} + +static NEXT: NativeFunction = native_fn(|mut this, _| { + let dynamic = match this.get_mut()? { + Val::Dynamic(dynamic) => dynamic, + _ => return Err("TODO: indirection".to_error()), + }; + + let iter = dynamic_make_mut(dynamic) + .as_any_mut() + .downcast_mut::() + .ok_or_else(|| "ArrayEntriesIterator.next called on different object".to_type_error())?; + + match iter.array.elements.get(iter.index) { + Some(item) => { + let res = Ok( + IterationResult { + value: vec![(iter.index as f64).to_val(), item.clone()].to_val(), + done: false, + } + .to_dynamic_val(), + ); + + iter.index += 1; + + res + } + None => Ok( + IterationResult { + value: Val::Undefined, + done: true, + } + .to_dynamic_val(), + ), + } +}); diff --git a/valuescript_vm/src/iteration/mod.rs b/valuescript_vm/src/iteration/mod.rs index 9547e32..58dc0eb 100644 --- a/valuescript_vm/src/iteration/mod.rs +++ b/valuescript_vm/src/iteration/mod.rs @@ -1,3 +1,4 @@ +pub mod array_entries_iterator; pub mod array_iterator; pub mod iteration_result; pub mod string_iterator; diff --git a/valuescript_vm/src/iteration/string_iterator.rs b/valuescript_vm/src/iteration/string_iterator.rs index 7d5b8c2..603d5a7 100644 --- a/valuescript_vm/src/iteration/string_iterator.rs +++ b/valuescript_vm/src/iteration/string_iterator.rs @@ -148,10 +148,8 @@ static NEXT: NativeFunction = native_fn(|mut this, _| { .downcast_mut::() .ok_or_else(|| "StringIterator.next called on different object".to_type_error())?; - let char = iter.next(); - Ok( - match char { + match iter.next() { Some(c) => IterationResult { value: c.to_val(), done: false, diff --git a/valuescript_vm/src/string_methods.rs b/valuescript_vm/src/string_methods.rs index b009fc6..fe7af26 100644 --- a/valuescript_vm/src/string_methods.rs +++ b/valuescript_vm/src/string_methods.rs @@ -661,11 +661,9 @@ static VALUE_OF: NativeFunction = native_fn(|this, _params| { }) }); -static VALUES: NativeFunction = native_fn(|this, _params| { - Ok(match this.get() { - Val::String(string_data) => StringIterator::new(string_data.clone()).to_dynamic_val(), - _ => return Err("string indirection".to_error()), - }) +static VALUES: NativeFunction = native_fn(|this, _params| match this.get() { + Val::String(string_data) => Ok(StringIterator::new(string_data.clone()).to_dynamic_val()), + _ => Err("string indirection".to_error()), }); /** diff --git a/valuescript_vm/src/vs_array.rs b/valuescript_vm/src/vs_array.rs index c2f2bbe..4515b3d 100644 --- a/valuescript_vm/src/vs_array.rs +++ b/valuescript_vm/src/vs_array.rs @@ -12,6 +12,7 @@ use crate::array_higher_functions::{ use crate::builtins::error_builtin::ToError; use crate::builtins::type_error_builtin::ToTypeError; use crate::helpers::{to_wrapping_index, to_wrapping_index_clamped}; +use crate::iteration::array_entries_iterator::ArrayEntriesIterator; use crate::iteration::array_iterator::ArrayIterator; use crate::native_function::{native_fn, NativeFunction}; use crate::operations::op_triple_eq_impl; @@ -272,11 +273,9 @@ static COPY_WITHIN: NativeFunction = native_fn(|mut this, params| { }) }); -static ENTRIES: NativeFunction = native_fn(|this, _params| { - match this.get() { - Val::Array(_array_data) => return Err("TODO: iterators".to_error()), - _ => return Err("array indirection".to_error()), - }; +static ENTRIES: NativeFunction = native_fn(|this, _params| match this.get() { + Val::Array(array_data) => Ok(ArrayEntriesIterator::new(array_data.clone()).to_dynamic_val()), + _ => Err("array indirection".to_error()), }); static FILL: NativeFunction = native_fn(|mut this, params| { @@ -646,9 +645,7 @@ static UNSHIFT: NativeFunction = native_fn(|mut this, params| { }) }); -static VALUES: NativeFunction = native_fn(|this, _params| { - Ok(match this.get() { - Val::Array(array_data) => ArrayIterator::new(array_data.clone()).to_dynamic_val(), - _ => return Err("array indirection".to_error()), - }) +static VALUES: NativeFunction = native_fn(|this, _params| match this.get() { + Val::Array(array_data) => Ok(ArrayIterator::new(array_data.clone()).to_dynamic_val()), + _ => Err("array indirection".to_error()), });