From ea4571fe82f724a414670559183e7181e037ca0a Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Wed, 31 May 2023 17:29:11 +1000 Subject: [PATCH] wip generators --- .../src/array_higher_functions/array_every.rs | 10 +- .../array_higher_functions/array_filter.rs | 6 +- .../src/array_higher_functions/array_find.rs | 10 +- .../array_find_index.rs | 10 +- .../array_higher_functions/array_flat_map.rs | 6 +- .../src/array_higher_functions/array_map.rs | 6 +- .../array_mapping_frame.rs | 14 +- .../array_higher_functions/array_reduce.rs | 7 +- .../array_reduce_right.rs | 9 +- .../src/array_higher_functions/array_some.rs | 10 +- .../src/array_higher_functions/array_sort.rs | 10 +- valuescript_vm/src/builtins/builtin_object.rs | 2 +- valuescript_vm/src/builtins/number_builtin.rs | 22 +-- valuescript_vm/src/bytecode_decoder.rs | 10 +- valuescript_vm/src/bytecode_stack_frame.rs | 6 + valuescript_vm/src/cat_stack_frame.rs | 10 +- valuescript_vm/src/first_stack_frame.rs | 7 + valuescript_vm/src/generator.rs | 139 ++++++++++++++++++ .../src/iteration/array_entries_iterator.rs | 2 +- .../src/iteration/array_iterator.rs | 2 +- .../src/iteration/iteration_result.rs | 2 +- .../src/iteration/string_iterator.rs | 2 +- valuescript_vm/src/lib.rs | 2 + valuescript_vm/src/make_generator_frame.rs | 60 ++++++++ valuescript_vm/src/native_frame_function.rs | 7 + valuescript_vm/src/stack_frame.rs | 7 + valuescript_vm/src/vs_function.rs | 20 ++- 27 files changed, 353 insertions(+), 45 deletions(-) create mode 100644 valuescript_vm/src/generator.rs create mode 100644 valuescript_vm/src/make_generator_frame.rs diff --git a/valuescript_vm/src/array_higher_functions/array_every.rs b/valuescript_vm/src/array_higher_functions/array_every.rs index 540fe31..84910c4 100644 --- a/valuescript_vm/src/array_higher_functions/array_every.rs +++ b/valuescript_vm/src/array_higher_functions/array_every.rs @@ -1,12 +1,12 @@ -use super::super::vs_value::{Val, ValTrait}; use super::super::native_frame_function::NativeFrameFunction; -use super::array_mapping_frame::{ArrayMappingState, ArrayMappingFrame}; +use super::super::vs_value::{Val, ValTrait}; +use super::array_mapping_frame::{ArrayMappingFrame, ArrayMappingState}; pub static EVERY: NativeFrameFunction = NativeFrameFunction { make_frame: || Box::new(ArrayMappingFrame::new(Box::new(EveryState::default()))), }; -#[derive(Default)] +#[derive(Default, Clone)] struct EveryState {} impl ArrayMappingState for EveryState { @@ -20,4 +20,8 @@ impl ArrayMappingState for EveryState { fn finish(&mut self) -> Val { Val::Bool(true) } + + fn clone_to_array_mapping_state(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/array_higher_functions/array_filter.rs b/valuescript_vm/src/array_higher_functions/array_filter.rs index 17a0bac..5bb1793 100644 --- a/valuescript_vm/src/array_higher_functions/array_filter.rs +++ b/valuescript_vm/src/array_higher_functions/array_filter.rs @@ -8,7 +8,7 @@ pub static FILTER: NativeFrameFunction = NativeFrameFunction { make_frame: || Box::new(ArrayMappingFrame::new(Box::new(FilterState::default()))), }; -#[derive(Default)] +#[derive(Default, Clone)] struct FilterState { filter_results: Vec, } @@ -27,4 +27,8 @@ impl ArrayMappingState for FilterState { std::mem::swap(&mut self.filter_results, &mut filter_results); filter_results.to_val() } + + fn clone_to_array_mapping_state(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/array_higher_functions/array_find.rs b/valuescript_vm/src/array_higher_functions/array_find.rs index b96a076..959473f 100644 --- a/valuescript_vm/src/array_higher_functions/array_find.rs +++ b/valuescript_vm/src/array_higher_functions/array_find.rs @@ -1,12 +1,12 @@ -use super::super::vs_value::{Val, ValTrait}; use super::super::native_frame_function::NativeFrameFunction; -use super::array_mapping_frame::{ArrayMappingState, ArrayMappingFrame}; +use super::super::vs_value::{Val, ValTrait}; +use super::array_mapping_frame::{ArrayMappingFrame, ArrayMappingState}; pub static FIND: NativeFrameFunction = NativeFrameFunction { make_frame: || Box::new(ArrayMappingFrame::new(Box::new(FindState::default()))), }; -#[derive(Default)] +#[derive(Default, Clone)] struct FindState {} impl ArrayMappingState for FindState { @@ -20,4 +20,8 @@ impl ArrayMappingState for FindState { fn finish(&mut self) -> Val { Val::Undefined } + + fn clone_to_array_mapping_state(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/array_higher_functions/array_find_index.rs b/valuescript_vm/src/array_higher_functions/array_find_index.rs index 07207c2..b5eb4d7 100644 --- a/valuescript_vm/src/array_higher_functions/array_find_index.rs +++ b/valuescript_vm/src/array_higher_functions/array_find_index.rs @@ -1,12 +1,12 @@ -use super::super::vs_value::{Val, ValTrait}; use super::super::native_frame_function::NativeFrameFunction; -use super::array_mapping_frame::{ArrayMappingState, ArrayMappingFrame}; +use super::super::vs_value::{Val, ValTrait}; +use super::array_mapping_frame::{ArrayMappingFrame, ArrayMappingState}; pub static FIND_INDEX: NativeFrameFunction = NativeFrameFunction { make_frame: || Box::new(ArrayMappingFrame::new(Box::new(FindIndexState::default()))), }; -#[derive(Default)] +#[derive(Default, Clone)] struct FindIndexState {} impl ArrayMappingState for FindIndexState { @@ -20,4 +20,8 @@ impl ArrayMappingState for FindIndexState { fn finish(&mut self) -> Val { Val::Number(-1f64) } + + fn clone_to_array_mapping_state(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/array_higher_functions/array_flat_map.rs b/valuescript_vm/src/array_higher_functions/array_flat_map.rs index 4c5d3ef..0f0e65f 100644 --- a/valuescript_vm/src/array_higher_functions/array_flat_map.rs +++ b/valuescript_vm/src/array_higher_functions/array_flat_map.rs @@ -8,7 +8,7 @@ pub static FLAT_MAP: NativeFrameFunction = NativeFrameFunction { make_frame: || Box::new(ArrayMappingFrame::new(Box::new(FlatMapState::default()))), }; -#[derive(Default)] +#[derive(Default, Clone)] struct FlatMapState { flat_map_results: Vec, } @@ -32,4 +32,8 @@ impl ArrayMappingState for FlatMapState { std::mem::swap(&mut self.flat_map_results, &mut flat_map_results); flat_map_results.to_val() } + + fn clone_to_array_mapping_state(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/array_higher_functions/array_map.rs b/valuescript_vm/src/array_higher_functions/array_map.rs index 04ba679..7d4dfca 100644 --- a/valuescript_vm/src/array_higher_functions/array_map.rs +++ b/valuescript_vm/src/array_higher_functions/array_map.rs @@ -8,7 +8,7 @@ pub static MAP: NativeFrameFunction = NativeFrameFunction { make_frame: || Box::new(ArrayMappingFrame::new(Box::new(MapState::default()))), }; -#[derive(Default)] +#[derive(Default, Clone)] struct MapState { map_results: Vec, } @@ -24,4 +24,8 @@ impl ArrayMappingState for MapState { std::mem::swap(&mut self.map_results, &mut map_results); map_results.to_val() } + + fn clone_to_array_mapping_state(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/array_higher_functions/array_mapping_frame.rs b/valuescript_vm/src/array_higher_functions/array_mapping_frame.rs index 8be0c85..17df4a1 100644 --- a/valuescript_vm/src/array_higher_functions/array_mapping_frame.rs +++ b/valuescript_vm/src/array_higher_functions/array_mapping_frame.rs @@ -2,16 +2,24 @@ use std::rc::Rc; use crate::builtins::type_error_builtin::ToTypeError; use crate::native_function::ThisWrapper; -use crate::stack_frame::FrameStepResult; use crate::stack_frame::{CallResult, FrameStepOk, StackFrameTrait}; +use crate::stack_frame::{FrameStepResult, StackFrame}; use crate::vs_array::VsArray; use crate::vs_value::{LoadFunctionResult, Val, ValTrait}; pub trait ArrayMappingState { fn process(&mut self, i: usize, element: &Val, mapped: Val) -> Option; fn finish(&mut self) -> Val; + fn clone_to_array_mapping_state(&self) -> Box; } +impl Clone for Box { + fn clone(&self) -> Self { + self.clone_to_array_mapping_state() + } +} + +#[derive(Clone)] pub struct ArrayMappingFrame { state: Box, early_exit: Option>, @@ -141,4 +149,8 @@ impl StackFrameTrait for ArrayMappingFrame { fn catch_exception(&mut self, _exception: Val) -> bool { return false; } + + fn clone_to_stack_frame(&self) -> StackFrame { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/array_higher_functions/array_reduce.rs b/valuescript_vm/src/array_higher_functions/array_reduce.rs index e3d2b99..5a23deb 100644 --- a/valuescript_vm/src/array_higher_functions/array_reduce.rs +++ b/valuescript_vm/src/array_higher_functions/array_reduce.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use crate::builtins::type_error_builtin::ToTypeError; use crate::native_frame_function::NativeFrameFunction; use crate::native_function::ThisWrapper; -use crate::stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrameTrait}; +use crate::stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrame, StackFrameTrait}; use crate::vs_array::VsArray; use crate::vs_value::{LoadFunctionResult, Val, ValTrait}; @@ -19,6 +19,7 @@ pub static REDUCE: NativeFrameFunction = NativeFrameFunction { }, }; +#[derive(Clone)] struct ReduceFrame { this: Option>, array_i: usize, @@ -113,4 +114,8 @@ impl StackFrameTrait for ReduceFrame { fn catch_exception(&mut self, _exception: Val) -> bool { return false; } + + fn clone_to_stack_frame(&self) -> StackFrame { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/array_higher_functions/array_reduce_right.rs b/valuescript_vm/src/array_higher_functions/array_reduce_right.rs index 1362939..97e4ce3 100644 --- a/valuescript_vm/src/array_higher_functions/array_reduce_right.rs +++ b/valuescript_vm/src/array_higher_functions/array_reduce_right.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use crate::builtins::type_error_builtin::ToTypeError; use crate::native_frame_function::NativeFrameFunction; use crate::native_function::ThisWrapper; -use crate::stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrameTrait}; +use crate::stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrame, StackFrameTrait}; use crate::vs_array::VsArray; use crate::vs_value::{LoadFunctionResult, Val, ValTrait}; @@ -19,6 +19,7 @@ pub static REDUCE_RIGHT: NativeFrameFunction = NativeFrameFunction { }, }; +#[derive(Clone)] struct ReduceRightFrame { this: Option>, array_i: usize, @@ -124,6 +125,10 @@ impl StackFrameTrait for ReduceRightFrame { } fn catch_exception(&mut self, _exception: Val) -> bool { - return false; + false + } + + fn clone_to_stack_frame(&self) -> StackFrame { + Box::new(self.clone()) } } diff --git a/valuescript_vm/src/array_higher_functions/array_some.rs b/valuescript_vm/src/array_higher_functions/array_some.rs index 6e8ab96..e8b8f1f 100644 --- a/valuescript_vm/src/array_higher_functions/array_some.rs +++ b/valuescript_vm/src/array_higher_functions/array_some.rs @@ -1,12 +1,12 @@ -use super::super::vs_value::{Val, ValTrait}; use super::super::native_frame_function::NativeFrameFunction; -use super::array_mapping_frame::{ArrayMappingState, ArrayMappingFrame}; +use super::super::vs_value::{Val, ValTrait}; +use super::array_mapping_frame::{ArrayMappingFrame, ArrayMappingState}; pub static SOME: NativeFrameFunction = NativeFrameFunction { make_frame: || Box::new(ArrayMappingFrame::new(Box::new(SomeState::default()))), }; -#[derive(Default)] +#[derive(Default, Clone)] struct SomeState {} impl ArrayMappingState for SomeState { @@ -20,4 +20,8 @@ impl ArrayMappingState for SomeState { fn finish(&mut self) -> Val { Val::Bool(false) } + + fn clone_to_array_mapping_state(&self) -> Box { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/array_higher_functions/array_sort.rs b/valuescript_vm/src/array_higher_functions/array_sort.rs index c17f39b..93d5711 100644 --- a/valuescript_vm/src/array_higher_functions/array_sort.rs +++ b/valuescript_vm/src/array_higher_functions/array_sort.rs @@ -3,8 +3,8 @@ use std::rc::Rc; use crate::builtins::type_error_builtin::ToTypeError; use crate::native_frame_function::NativeFrameFunction; use crate::native_function::ThisWrapper; -use crate::stack_frame::FrameStepResult; use crate::stack_frame::{CallResult, FrameStepOk, StackFrameTrait}; +use crate::stack_frame::{FrameStepResult, StackFrame}; use crate::vs_array::VsArray; use crate::vs_value::{LoadFunctionResult, ToVal, Val, ValTrait}; @@ -22,6 +22,7 @@ pub static SORT: NativeFrameFunction = NativeFrameFunction { }, }; +#[derive(Clone)] struct SortFrame { this: Option>, @@ -32,6 +33,7 @@ struct SortFrame { started: bool, } +#[derive(Clone)] struct VecPos { vec: Vec, pos: usize, @@ -43,6 +45,7 @@ struct VecSlice<'a, T> { end: usize, } +#[derive(Clone)] struct SortTreeNode { data: SortTreeNodeData, } @@ -199,6 +202,7 @@ impl SortTreeNode { } } +#[derive(Clone)] enum SortTreeNodeData { Branch(Box, Box), Sorting(Vec, VecPos, VecPos), @@ -318,4 +322,8 @@ impl StackFrameTrait for SortFrame { fn catch_exception(&mut self, _exception: Val) -> bool { false } + + fn clone_to_stack_frame(&self) -> StackFrame { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/builtins/builtin_object.rs b/valuescript_vm/src/builtins/builtin_object.rs index fb1d47a..963ad64 100644 --- a/valuescript_vm/src/builtins/builtin_object.rs +++ b/valuescript_vm/src/builtins/builtin_object.rs @@ -27,7 +27,7 @@ where } fn to_number(&self) -> f64 { - core::f64::NAN + f64::NAN } fn to_index(&self) -> Option { diff --git a/valuescript_vm/src/builtins/number_builtin.rs b/valuescript_vm/src/builtins/number_builtin.rs index e15588f..8f44213 100644 --- a/valuescript_vm/src/builtins/number_builtin.rs +++ b/valuescript_vm/src/builtins/number_builtin.rs @@ -21,14 +21,14 @@ impl BuiltinObject for NumberBuiltin { fn bo_sub(key: &str) -> Val { match key { - "EPSILON" => core::f64::EPSILON.to_val(), - "MAX_VALUE" => core::f64::MAX.to_val(), + "EPSILON" => f64::EPSILON.to_val(), + "MAX_VALUE" => f64::MAX.to_val(), "MAX_SAFE_INTEGER" => (2f64.powi(53) - 1f64).to_val(), "MIN_SAFE_INTEGER" => (-(2f64.powi(53) - 1f64)).to_val(), - "MIN_VALUE" => core::f64::MIN_POSITIVE.to_val(), - "NEGATIVE_INFINITY" => core::f64::NEG_INFINITY.to_val(), - "POSITIVE_INFINITY" => core::f64::INFINITY.to_val(), - "NaN" => core::f64::NAN.to_val(), + "MIN_VALUE" => f64::MIN_POSITIVE.to_val(), + "NEGATIVE_INFINITY" => f64::NEG_INFINITY.to_val(), + "POSITIVE_INFINITY" => f64::INFINITY.to_val(), + "NaN" => f64::NAN.to_val(), "isFinite" => IS_FINITE.to_val(), "isInteger" => IS_INTEGER.to_val(), "isNaN" => IS_NAN.to_val(), @@ -111,10 +111,10 @@ pub static PARSE_FLOAT: NativeFunction = native_fn(|_this, params| { match string_value.parse::() { Ok(number) => Val::Number(number), - Err(_) => Val::Number(core::f64::NAN), + Err(_) => Val::Number(f64::NAN), } } else { - Val::Number(core::f64::NAN) + Val::Number(f64::NAN) }) }); @@ -124,7 +124,7 @@ pub static PARSE_INT: NativeFunction = native_fn(|_this, params| { let radix = params.get(1).and_then(|v| v.to_index()).unwrap_or(10); if radix < 2 || radix > 36 { - return Ok(Val::Number(core::f64::NAN)); + return Ok(Val::Number(f64::NAN)); } let (is_negative, string_value) = if string_value.starts_with('-') { @@ -143,9 +143,9 @@ pub static PARSE_INT: NativeFunction = native_fn(|_this, params| { let number = if is_negative { -number } else { number }; Val::Number(number as f64) } - Err(_) => Val::Number(core::f64::NAN), + Err(_) => Val::Number(f64::NAN), } } else { - Val::Number(core::f64::NAN) + Val::Number(f64::NAN) }) }); diff --git a/valuescript_vm/src/bytecode_decoder.rs b/valuescript_vm/src/bytecode_decoder.rs index 40253bc..db69149 100644 --- a/valuescript_vm/src/bytecode_decoder.rs +++ b/valuescript_vm/src/bytecode_decoder.rs @@ -14,6 +14,7 @@ use crate::vs_symbol::VsSymbol; use crate::vs_value::ToVal; use crate::vs_value::Val; +#[derive(Clone)] pub struct BytecodeDecoder { // TODO: Enable borrow usage to avoid the rc overhead pub bytecode: Rc, @@ -40,6 +41,7 @@ pub enum BytecodeType { Builtin = 0x10, Class = 0x11, BigInt = 0x13, + GeneratorFunction = 0x14, Unrecognized = 0xff, } @@ -62,10 +64,12 @@ impl BytecodeType { 0x0b => Function, 0x0d => Pointer, 0x0e => Register, + 0x10 => Builtin, 0x11 => Class, 0x13 => BigInt, + 0x14 => GeneratorFunction, _ => Unrecognized, }; @@ -127,7 +131,7 @@ impl BytecodeDecoder { } .to_val() } - BytecodeType::Function => self.decode_function_header(), + BytecodeType::Function => self.decode_function(false), BytecodeType::Pointer => self.decode_pointer(registers), BytecodeType::Register => match registers[self.decode_register_index().unwrap()].clone() { Val::Void => Val::Undefined, @@ -140,6 +144,7 @@ impl BytecodeDecoder { } .to_val(), BytecodeType::BigInt => self.decode_bigint().to_val(), + BytecodeType::GeneratorFunction => self.decode_function(true), BytecodeType::Unrecognized => panic!("Unrecognized bytecode type at {}", self.pos - 1), }; } @@ -270,13 +275,14 @@ impl BytecodeDecoder { } } - pub fn decode_function_header(&mut self) -> Val { + pub fn decode_function(&mut self, is_generator: bool) -> Val { // TODO: Support >256 let register_count = self.decode_byte() as usize; let parameter_count = self.decode_byte() as usize; return VsFunction { bytecode: self.bytecode.clone(), + is_generator, register_count, parameter_count, start: self.pos, diff --git a/valuescript_vm/src/bytecode_stack_frame.rs b/valuescript_vm/src/bytecode_stack_frame.rs index 2250d00..1501258 100644 --- a/valuescript_vm/src/bytecode_stack_frame.rs +++ b/valuescript_vm/src/bytecode_stack_frame.rs @@ -13,6 +13,7 @@ use crate::vs_object::VsObject; use crate::vs_value::ToVal; use crate::vs_value::{LoadFunctionResult, Val, ValTrait}; +#[derive(Clone)] pub struct BytecodeStackFrame { pub decoder: BytecodeDecoder, pub registers: Vec, @@ -24,6 +25,7 @@ pub struct BytecodeStackFrame { pub catch_setting: Option, } +#[derive(Clone)] pub struct CatchSetting { pub pos: usize, pub register: Option, @@ -592,6 +594,10 @@ impl StackFrameTrait for BytecodeStackFrame { false } } + + fn clone_to_stack_frame(&self) -> StackFrame { + Box::new(self.clone()) + } } enum ThisArg { diff --git a/valuescript_vm/src/cat_stack_frame.rs b/valuescript_vm/src/cat_stack_frame.rs index 0914b24..6c02a7f 100644 --- a/valuescript_vm/src/cat_stack_frame.rs +++ b/valuescript_vm/src/cat_stack_frame.rs @@ -4,13 +4,13 @@ use crate::{ builtins::type_error_builtin::ToTypeError, native_function::ThisWrapper, operations::op_sub, - stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrameTrait}, + stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrame, StackFrameTrait}, vs_symbol::VsSymbol, vs_value::{ToVal, Val}, LoadFunctionResult, ValTrait, }; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct CatStackFrame { pub state: CatFrameState, pub iter_result: Option, @@ -19,7 +19,7 @@ pub struct CatStackFrame { pub res: Vec, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum CatFrameState { ReadNext, MakingIterator, @@ -146,4 +146,8 @@ impl StackFrameTrait for CatStackFrame { fn catch_exception(&mut self, _exception: Val) -> bool { false } + + fn clone_to_stack_frame(&self) -> StackFrame { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/first_stack_frame.rs b/valuescript_vm/src/first_stack_frame.rs index 96d6142..8e1f9eb 100644 --- a/valuescript_vm/src/first_stack_frame.rs +++ b/valuescript_vm/src/first_stack_frame.rs @@ -1,6 +1,9 @@ +use crate::stack_frame::StackFrame; + use super::stack_frame::{CallResult, FrameStepResult, StackFrameTrait}; use super::vs_value::Val; +#[derive(Clone)] pub struct FirstStackFrame { call_result: CallResult, } @@ -40,4 +43,8 @@ impl StackFrameTrait for FirstStackFrame { fn catch_exception(&mut self, _exception: Val) -> bool { panic!("Not appropriate for FirstStackFrame"); } + + fn clone_to_stack_frame(&self) -> StackFrame { + Box::new(self.clone()) + } } diff --git a/valuescript_vm/src/generator.rs b/valuescript_vm/src/generator.rs new file mode 100644 index 0000000..a01572f --- /dev/null +++ b/valuescript_vm/src/generator.rs @@ -0,0 +1,139 @@ +use std::{fmt, rc::Rc}; + +use num_bigint::BigInt; + +use crate::{ + builtins::type_error_builtin::ToTypeError, + iteration::{iteration_result::IterationResult, return_this::RETURN_THIS}, + native_function::{native_fn, NativeFunction}, + stack_frame::StackFrame, + vs_array::VsArray, + vs_class::VsClass, + vs_symbol::VsSymbol, + vs_value::{ToDynamicVal, ToVal, Val, VsType}, + LoadFunctionResult, ValTrait, +}; + +#[derive(Clone)] +pub struct Generator { + #[allow(dead_code)] // TODO + frame: StackFrame, + + #[allow(dead_code)] // TODO + stack: Vec, +} + +impl Generator { + pub fn new(frame: StackFrame) -> Generator { + return Generator { + frame, + stack: vec![], + }; + } +} + +impl ValTrait for Generator { + fn typeof_(&self) -> VsType { + VsType::Object + } + + fn to_number(&self) -> f64 { + 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 { + // TODO: Add symbol for next for performance? (Still needs this fallback) + if key.to_string() == "next" { + return Ok(NEXT.to_val()); + } + + if let Val::Symbol(VsSymbol::ITERATOR) = key { + return Ok(RETURN_THIS.to_val()); + } + + Ok(Val::Undefined) + } + + fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> { + Err("Cannot assign to subscript of a generator".to_type_error()) + } + + fn pretty_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "\x1b[36m[Generator]\x1b[39m") + } + + fn codify(&self) -> String { + "Generator {{ [native data] }}".to_string() + } +} + +impl fmt::Display for Generator { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[object Generator]") + } +} + +// We can't use a native function for this. It needs to make a new frame which implements step by +// stepping the contained stack. +// +// Note that next() requires copying the stack in the general case since exceptions must revert the +// iterator. One practical solution for this might be to detect when the generator is in a state +// where it doesn't use the result of the yield expression and reason that a subsequent next() call +// must have the same output, therefore it can store the generated exception in that case instead of +// needing to copy. +// +static NEXT: NativeFunction = native_fn(|mut _this, _| { + // let dynamic = match this.get_mut()? { + // Val::Dynamic(dynamic) => dynamic, + // _ => return Err("TODO: indirection".to_error()), + // }; + + // let _generator = dynamic_make_mut(dynamic) + // .as_any_mut() + // .downcast_mut::() + // .ok_or_else(|| "Generator.next called on different object".to_type_error())?; + + Ok( + IterationResult { + value: "TODO".to_val(), + done: false, + } + .to_dynamic_val(), + ) +}); diff --git a/valuescript_vm/src/iteration/array_entries_iterator.rs b/valuescript_vm/src/iteration/array_entries_iterator.rs index 991979e..fc93e12 100644 --- a/valuescript_vm/src/iteration/array_entries_iterator.rs +++ b/valuescript_vm/src/iteration/array_entries_iterator.rs @@ -32,7 +32,7 @@ impl ValTrait for ArrayEntriesIterator { } fn to_number(&self) -> f64 { - core::f64::NAN + f64::NAN } fn to_index(&self) -> Option { diff --git a/valuescript_vm/src/iteration/array_iterator.rs b/valuescript_vm/src/iteration/array_iterator.rs index 0330e02..c0047d5 100644 --- a/valuescript_vm/src/iteration/array_iterator.rs +++ b/valuescript_vm/src/iteration/array_iterator.rs @@ -32,7 +32,7 @@ impl ValTrait for ArrayIterator { } fn to_number(&self) -> f64 { - core::f64::NAN + f64::NAN } fn to_index(&self) -> Option { diff --git a/valuescript_vm/src/iteration/iteration_result.rs b/valuescript_vm/src/iteration/iteration_result.rs index 002f871..0348162 100644 --- a/valuescript_vm/src/iteration/iteration_result.rs +++ b/valuescript_vm/src/iteration/iteration_result.rs @@ -22,7 +22,7 @@ impl ValTrait for IterationResult { } fn to_number(&self) -> f64 { - core::f64::NAN + f64::NAN } fn to_index(&self) -> Option { diff --git a/valuescript_vm/src/iteration/string_iterator.rs b/valuescript_vm/src/iteration/string_iterator.rs index f365c40..78e59a3 100644 --- a/valuescript_vm/src/iteration/string_iterator.rs +++ b/valuescript_vm/src/iteration/string_iterator.rs @@ -68,7 +68,7 @@ impl ValTrait for StringIterator { } fn to_number(&self) -> f64 { - core::f64::NAN + f64::NAN } fn to_index(&self) -> Option { diff --git a/valuescript_vm/src/lib.rs b/valuescript_vm/src/lib.rs index 5c6b351..10fb8f8 100644 --- a/valuescript_vm/src/lib.rs +++ b/valuescript_vm/src/lib.rs @@ -6,8 +6,10 @@ mod bytecode_decoder; mod bytecode_stack_frame; mod cat_stack_frame; mod first_stack_frame; +mod generator; mod helpers; mod iteration; +mod make_generator_frame; mod native_frame_function; mod native_function; mod number_methods; diff --git a/valuescript_vm/src/make_generator_frame.rs b/valuescript_vm/src/make_generator_frame.rs new file mode 100644 index 0000000..2633215 --- /dev/null +++ b/valuescript_vm/src/make_generator_frame.rs @@ -0,0 +1,60 @@ +use std::mem::take; + +use crate::{ + bytecode_stack_frame::BytecodeStackFrame, + generator::Generator, + stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrame, StackFrameTrait}, + vs_value::{ToDynamicVal, Val}, +}; + +#[derive(Clone)] +pub struct MakeGeneratorFrame { + pub frame: Option, +} + +impl MakeGeneratorFrame { + pub fn new(frame: BytecodeStackFrame) -> MakeGeneratorFrame { + return MakeGeneratorFrame { frame: Some(frame) }; + } + + fn frame_mut(&mut self) -> &mut BytecodeStackFrame { + self.frame.as_mut().unwrap() + } + + fn take_frame(&mut self) -> BytecodeStackFrame { + take(&mut self.frame).unwrap() + } +} + +impl StackFrameTrait for MakeGeneratorFrame { + fn write_this(&mut self, const_: bool, this: Val) -> Result<(), Val> { + self.frame_mut().write_this(const_, this) + } + + fn write_param(&mut self, param: Val) { + self.frame_mut().write_param(param); + } + + fn step(&mut self) -> FrameStepResult { + Ok(FrameStepOk::Pop(CallResult { + return_: Generator::new(Box::new(self.take_frame())).to_dynamic_val(), + this: Val::Undefined, + })) + } + + fn apply_call_result(&mut self, _call_result: CallResult) { + panic!("Not appropriate for MakeGeneratorFrame"); + } + + fn get_call_result(&mut self) -> CallResult { + panic!("Not appropriate for MakeGeneratorFrame") + } + + fn catch_exception(&mut self, _exception: Val) -> bool { + panic!("Not appropriate for MakeGeneratorFrame"); + } + + fn clone_to_stack_frame(&self) -> StackFrame { + Box::new(self.clone()) + } +} diff --git a/valuescript_vm/src/native_frame_function.rs b/valuescript_vm/src/native_frame_function.rs index af141a4..bd4e8e0 100644 --- a/valuescript_vm/src/native_frame_function.rs +++ b/valuescript_vm/src/native_frame_function.rs @@ -18,18 +18,23 @@ impl ValTrait for NativeFrameFunction { fn typeof_(&self) -> VsType { VsType::Function } + fn to_number(&self) -> f64 { 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 } @@ -41,9 +46,11 @@ impl ValTrait for NativeFrameFunction { fn as_bigint_data(&self) -> Option { None } + fn as_array_data(&self) -> Option> { None } + fn as_class_data(&self) -> Option> { None } diff --git a/valuescript_vm/src/stack_frame.rs b/valuescript_vm/src/stack_frame.rs index a5ff93c..c8d6a52 100644 --- a/valuescript_vm/src/stack_frame.rs +++ b/valuescript_vm/src/stack_frame.rs @@ -23,4 +23,11 @@ pub trait StackFrameTrait { fn apply_call_result(&mut self, call_result: CallResult); fn get_call_result(&mut self) -> CallResult; fn catch_exception(&mut self, exception: Val) -> bool; + fn clone_to_stack_frame(&self) -> StackFrame; +} + +impl Clone for StackFrame { + fn clone(&self) -> Self { + self.clone_to_stack_frame() + } } diff --git a/valuescript_vm/src/vs_function.rs b/valuescript_vm/src/vs_function.rs index 74040ee..618f7ac 100644 --- a/valuescript_vm/src/vs_function.rs +++ b/valuescript_vm/src/vs_function.rs @@ -1,6 +1,7 @@ use std::rc::Rc; use crate::bytecode::Bytecode; +use crate::make_generator_frame::MakeGeneratorFrame; use crate::vs_value::ToVal; use super::bytecode_decoder::BytecodeDecoder; @@ -8,9 +9,10 @@ use super::bytecode_stack_frame::BytecodeStackFrame; use super::stack_frame::StackFrame; use super::vs_value::Val; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct VsFunction { pub bytecode: Rc, + pub is_generator: bool, pub register_count: usize, pub parameter_count: usize, pub start: usize, @@ -27,6 +29,7 @@ impl VsFunction { return VsFunction { bytecode: self.bytecode.clone(), + is_generator: self.is_generator, register_count: self.register_count, parameter_count: self.parameter_count, start: self.start, @@ -34,7 +37,7 @@ impl VsFunction { }; } - pub fn make_frame(&self) -> StackFrame { + pub fn make_bytecode_frame(&self) -> BytecodeStackFrame { let mut registers: Vec = Vec::with_capacity(self.register_count - 1); registers.push(Val::Undefined); @@ -48,7 +51,7 @@ impl VsFunction { registers.push(Val::Void); } - return Box::new(BytecodeStackFrame { + return BytecodeStackFrame { decoder: BytecodeDecoder { bytecode: self.bytecode.clone(), pos: self.start, @@ -60,7 +63,16 @@ impl VsFunction { this_target: None, return_target: None, catch_setting: None, - }); + }; + } + + pub fn make_frame(&self) -> StackFrame { + let frame = self.make_bytecode_frame(); + + match self.is_generator { + false => Box::new(frame), + true => Box::new(MakeGeneratorFrame::new(frame)), + } } }