Implement ArrayIterator.next

This commit is contained in:
Andrew Morris
2023-05-29 12:45:38 +10:00
parent 4cfcb00e10
commit e7d008e3c9
3 changed files with 91 additions and 9 deletions

View File

@@ -3,13 +3,17 @@ use std::{fmt, rc::Rc};
use num_bigint::BigInt;
use crate::{
builtins::type_error_builtin::ToTypeError,
builtins::{error_builtin::ToError, type_error_builtin::ToTypeError},
native_function::{native_fn, NativeFunction},
vs_array::VsArray,
vs_class::VsClass,
vs_value::{Val, VsType},
vs_value::{dynamic_make_mut, ToDynamicVal, ToVal, Val, VsType},
LoadFunctionResult, ValTrait,
};
use super::iteration_result::IterationResult;
#[derive(Clone)]
pub struct ArrayIterator {
pub array: Rc<VsArray>,
pub index: usize,
@@ -66,8 +70,12 @@ impl ValTrait for ArrayIterator {
LoadFunctionResult::NotAFunction
}
fn sub(&self, _key: Val) -> Result<Val, Val> {
todo!()
fn sub(&self, key: Val) -> Result<Val, Val> {
if key.to_string() == "next" {
return Ok(NEXT.to_val());
}
Ok(Val::Undefined)
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
@@ -92,3 +100,36 @@ impl fmt::Display for ArrayIterator {
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::<ArrayIterator>()
.ok_or_else(|| "ArrayIterator.next called on different object".to_type_error())?;
match iter.array.elements.get(iter.index) {
Some(item) => {
iter.index += 1;
Ok(
IterationResult {
value: item.clone(),
done: false,
}
.to_dynamic_val(),
)
}
None => Ok(
IterationResult {
value: Val::Undefined,
done: true,
}
.to_dynamic_val(),
),
}
});

View File

@@ -10,7 +10,8 @@ use crate::{
LoadFunctionResult, ValTrait,
};
struct IterationResult {
#[derive(Clone)]
pub struct IterationResult {
pub value: Val,
pub done: bool,
}
@@ -74,8 +75,8 @@ impl ValTrait for IterationResult {
fn pretty_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.done {
false => write!(f, "\x1b[36mIteration({})\x1b[39m", self.value.pretty()),
true => write!(f, "\x1b[36mIterationDone({})\x1b[39m", self.value.pretty()),
false => write!(f, "Iteration({})", self.value.pretty()),
true => write!(f, "IterationDone({})", self.value.pretty()),
}
}

View File

@@ -1,4 +1,5 @@
use core::fmt;
use std::any::Any;
use std::rc::Rc;
use std::str::FromStr;
@@ -30,7 +31,7 @@ pub enum Val {
Function(Rc<VsFunction>),
Class(Rc<VsClass>),
Static(&'static dyn ValTrait),
Dynamic(Rc<dyn ValTrait>),
Dynamic(Rc<dyn DynValTrait>),
}
#[derive(PartialEq, Debug)]
@@ -77,6 +78,37 @@ pub trait ValTrait: fmt::Display {
fn codify(&self) -> String;
}
pub trait DynValTrait: ValTrait {
fn clone_interior(&self) -> Rc<dyn DynValTrait>;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl<T> DynValTrait for T
where
T: 'static + ValTrait + Clone,
{
fn clone_interior(&self) -> Rc<dyn DynValTrait> {
Rc::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
pub fn dynamic_make_mut(rc: &mut Rc<dyn DynValTrait>) -> &mut dyn DynValTrait {
if Rc::get_mut(rc).is_none() {
*rc = rc.clone_interior();
}
Rc::get_mut(rc).unwrap()
}
impl fmt::Debug for dyn ValTrait {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(dyn ValTrait)(")?;
@@ -85,6 +117,14 @@ impl fmt::Debug for dyn ValTrait {
}
}
impl fmt::Debug for dyn DynValTrait {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(dyn DynValTrait)(")?;
self.pretty_fmt(f)?;
write!(f, ")")
}
}
impl Val {
pub fn to_primitive(&self) -> Val {
if self.is_primitive() {
@@ -510,7 +550,7 @@ pub trait ToDynamicVal {
impl<T> ToDynamicVal for T
where
T: ValTrait + 'static,
T: DynValTrait + 'static,
{
fn to_dynamic_val(self) -> Val {
Val::Dynamic(Rc::new(self))