diff --git a/src/vstc/virtual_machine/array_higher_functions/array_filter.rs b/src/vstc/virtual_machine/array_higher_functions/array_filter.rs new file mode 100644 index 0000000..98ffdea --- /dev/null +++ b/src/vstc/virtual_machine/array_higher_functions/array_filter.rs @@ -0,0 +1,112 @@ +use std::rc::Rc; + +use super::super::vs_value::{Val, ValTrait, LoadFunctionResult}; +use super::super::vs_array::VsArray; +use super::super::native_frame_function::NativeFrameFunction; +use super::super::stack_frame::{StackFrameTrait, FrameStepResult, CallResult}; + +pub static FILTER: NativeFrameFunction = NativeFrameFunction { + make_frame: || Box::new(FilterFrame { + this: None, + this_arg: Val::Undefined, + condition_fn: Val::Void, + param_i: 0, + array_i: 0, + filter_results: Vec::new(), + }), +}; + +struct FilterFrame { + this: Option>, + this_arg: Val, + condition_fn: Val, + param_i: usize, + array_i: usize, + filter_results: Vec, +} + +impl StackFrameTrait for FilterFrame { + fn write_this(&mut self, this: Val) { + self.this = this.as_array_data(); + } + + fn write_param(&mut self, param: Val) { + match self.param_i { + 0 => { self.condition_fn = param; } + 1 => { self.this_arg = param; } + _ => {}, + }; + + self.param_i += 1; + } + + fn step(&mut self) -> FrameStepResult { + let array_data = match &self.this { + None => std::panic!("Not implemented: exception: filter called on non-array"), + Some(ad) => ad, + }; + + let array_i = self.array_i; + self.array_i += 1; + + match array_data.elements.get(array_i) { + Some(el) => match el { + Val::Void => { + return FrameStepResult::Continue; + }, + _ => match self.condition_fn.load_function() { + LoadFunctionResult::NotAFunction => + std::panic!("Not implemented: exception: filter fn is not a function") + , + LoadFunctionResult::NativeFunction(native_fn) => { + let cond_result = native_fn( + &mut self.this_arg.clone(), + vec![ + el.clone(), + Val::Number(array_i as f64), + Val::Array(array_data.clone()), + ], + ); + + if cond_result.is_truthy() { + self.filter_results.push(el.clone()); + } + + return FrameStepResult::Continue; + }, + LoadFunctionResult::StackFrame(mut new_frame) => { + new_frame.write_this(self.this_arg.clone()); + new_frame.write_param(el.clone()); + new_frame.write_param(Val::Number(array_i as f64)); + new_frame.write_param(Val::Array(array_data.clone())); + return FrameStepResult::Push(new_frame); + }, + }, + }, + None => { + let mut return_elements = Vec::new(); + std::mem::swap(&mut return_elements, &mut self.filter_results); + + return FrameStepResult::Pop(CallResult { + return_: Val::Array(Rc::new(VsArray::from(return_elements))), + this: Val::Array(array_data.clone()), + }); + }, + }; + } + + fn apply_call_result(&mut self, call_result: CallResult) { + if call_result.return_.is_truthy() { + let array_data = match &self.this { + None => std::panic!("Not implemented: exception: filter called on non-array"), + Some(ad) => ad, + }; + + self.filter_results.push(array_data.elements[self.array_i - 1].clone()); + } + } + + fn get_call_result(&mut self) -> CallResult { + std::panic!("Not appropriate for FilterFrame") + } +} diff --git a/src/vstc/virtual_machine/array_higher_functions/mod.rs b/src/vstc/virtual_machine/array_higher_functions/mod.rs index c2de6ef..ef7f4e2 100644 --- a/src/vstc/virtual_machine/array_higher_functions/mod.rs +++ b/src/vstc/virtual_machine/array_higher_functions/mod.rs @@ -1,3 +1,4 @@ pub mod array_map; pub mod array_every; pub mod array_some; +pub mod array_filter; diff --git a/src/vstc/virtual_machine/vs_array.rs b/src/vstc/virtual_machine/vs_array.rs index 715a2d9..e256213 100644 --- a/src/vstc/virtual_machine/vs_array.rs +++ b/src/vstc/virtual_machine/vs_array.rs @@ -14,6 +14,7 @@ use super::operations::op_triple_eq_impl; use super::array_higher_functions::array_map::MAP; use super::array_higher_functions::array_every::EVERY; use super::array_higher_functions::array_some::SOME; +use super::array_higher_functions::array_filter::FILTER; #[derive(Clone)] pub struct VsArray { @@ -305,17 +306,6 @@ static FILL: NativeFunction = NativeFunction { } }; -static FILTER: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Val { - match this { - Val::Array(_array_data) => { - std::panic!("Not implemented: FILTER"); - }, - _ => std::panic!("Not implemented: exceptions/array indirection"), - }; - } -}; - static FIND: NativeFunction = NativeFunction { fn_: |this: &mut Val, _params: Vec| -> Val { match this {