From e54abc981f1ca0763c0deec88e56a964fb33c9de Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Tue, 4 Apr 2023 00:13:04 +1000 Subject: [PATCH] Make native functions const aware --- .../array_mapping_frame.rs | 3 +- .../array_higher_functions/array_reduce.rs | 3 +- .../array_reduce_right.rs | 3 +- .../src/array_higher_functions/array_sort.rs | 7 +- valuescript_vm/src/bigint_methods.rs | 12 +-- valuescript_vm/src/builtins/array_builtin.rs | 10 +- .../src/builtins/boolean_builtin.rs | 3 +- valuescript_vm/src/builtins/debug_builtin.rs | 4 +- valuescript_vm/src/builtins/error_builtin.rs | 15 ++- valuescript_vm/src/builtins/math_builtin.rs | 70 ++++++------- valuescript_vm/src/builtins/number_builtin.rs | 15 +-- .../src/builtins/range_error_builtin.rs | 19 ++-- valuescript_vm/src/builtins/string_builtin.rs | 5 +- .../src/builtins/type_error_builtin.rs | 19 ++-- valuescript_vm/src/bytecode_stack_frame.rs | 20 ++-- valuescript_vm/src/native_frame_function.rs | 1 + valuescript_vm/src/native_function.rs | 25 ++++- valuescript_vm/src/number_methods.rs | 25 ++--- valuescript_vm/src/operations.rs | 9 +- valuescript_vm/src/string_methods.rs | 98 +++++++++---------- valuescript_vm/src/todo_fn.rs | 10 +- valuescript_vm/src/vs_array.rs | 86 +++++++++------- valuescript_vm/src/vs_value.rs | 3 +- 23 files changed, 273 insertions(+), 192 deletions(-) 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 1b5ae0f..5b95f38 100644 --- a/valuescript_vm/src/array_higher_functions/array_mapping_frame.rs +++ b/valuescript_vm/src/array_higher_functions/array_mapping_frame.rs @@ -1,5 +1,6 @@ use std::rc::Rc; +use crate::native_function::ThisWrapper; use crate::stack_frame::FrameStepResult; use crate::stack_frame::{CallResult, FrameStepOk, StackFrameTrait}; use crate::vs_array::VsArray; @@ -86,7 +87,7 @@ impl StackFrameTrait for ArrayMappingFrame { array_i, el, native_fn( - &mut self.this_arg.clone(), + ThisWrapper::new(false, &mut self.this_arg.clone()), vec![ el.clone(), Val::Number(array_i as f64), diff --git a/valuescript_vm/src/array_higher_functions/array_reduce.rs b/valuescript_vm/src/array_higher_functions/array_reduce.rs index 15ce3a7..68ecbfd 100644 --- a/valuescript_vm/src/array_higher_functions/array_reduce.rs +++ b/valuescript_vm/src/array_higher_functions/array_reduce.rs @@ -1,6 +1,7 @@ use std::rc::Rc; use crate::native_frame_function::NativeFrameFunction; +use crate::native_function::ThisWrapper; use crate::stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrameTrait}; use crate::vs_array::VsArray; use crate::vs_value::{LoadFunctionResult, Val, ValTrait}; @@ -67,7 +68,7 @@ impl StackFrameTrait for ReduceFrame { LoadFunctionResult::NotAFunction => return type_error!("reduce fn is not a function"), LoadFunctionResult::NativeFunction(native_fn) => { self.value = Some(native_fn( - &mut Val::Undefined, + ThisWrapper::new(true, &mut Val::Undefined), vec![ value.clone(), el.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 c83ab91..3211155 100644 --- a/valuescript_vm/src/array_higher_functions/array_reduce_right.rs +++ b/valuescript_vm/src/array_higher_functions/array_reduce_right.rs @@ -1,6 +1,7 @@ use std::rc::Rc; use crate::native_frame_function::NativeFrameFunction; +use crate::native_function::ThisWrapper; use crate::stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrameTrait}; use crate::vs_array::VsArray; use crate::vs_value::{LoadFunctionResult, Val, ValTrait}; @@ -89,7 +90,7 @@ impl StackFrameTrait for ReduceRightFrame { } LoadFunctionResult::NativeFunction(native_fn) => { self.value = Some(native_fn( - &mut Val::Undefined, + ThisWrapper::new(true, &mut Val::Undefined), vec![ value.clone(), el.clone(), diff --git a/valuescript_vm/src/array_higher_functions/array_sort.rs b/valuescript_vm/src/array_higher_functions/array_sort.rs index 9520e0d..cdfc61b 100644 --- a/valuescript_vm/src/array_higher_functions/array_sort.rs +++ b/valuescript_vm/src/array_higher_functions/array_sort.rs @@ -1,6 +1,7 @@ use std::rc::Rc; 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::vs_array::VsArray; @@ -271,7 +272,11 @@ impl StackFrameTrait for SortFrame { return type_error!("comparator is not a function"); } LoadFunctionResult::NativeFunction(native_fn) => { - let res = native_fn(&mut Val::Undefined, vec![left, right])?.to_number(); + let res = native_fn( + ThisWrapper::new(true, &mut Val::Undefined), + vec![left, right], + )? + .to_number(); let should_swap = match res.is_nan() { true => false, diff --git a/valuescript_vm/src/bigint_methods.rs b/valuescript_vm/src/bigint_methods.rs index 0bbcc29..e4e049b 100644 --- a/valuescript_vm/src/bigint_methods.rs +++ b/valuescript_vm/src/bigint_methods.rs @@ -4,7 +4,7 @@ use num_bigint::BigInt; use crate::{ format_err, - native_function::NativeFunction, + native_function::{NativeFunction, ThisWrapper}, todo_fn::TODO, vs_value::{Val, ValTrait}, }; @@ -19,14 +19,14 @@ pub fn op_sub_bigint(_bigint: &BigInt, subscript: &Val) -> Val { } static TO_STRING: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::BigInt(_) => match params.get(0) { Some(_) => { return format_err!("TODO: toString with radix"); } - None => Val::String(Rc::new(this.val_to_string())), + None => Val::String(Rc::new(this.get().val_to_string())), }, _ => return format_err!("TODO: bigint indirection"), }) @@ -34,8 +34,8 @@ static TO_STRING: NativeFunction = NativeFunction { }; static VALUE_OF: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(match this.get() { Val::BigInt(bigint) => Val::BigInt(bigint.clone()), _ => return format_err!("TODO: bigint indirection"), }) diff --git a/valuescript_vm/src/builtins/array_builtin.rs b/valuescript_vm/src/builtins/array_builtin.rs index a3e7f68..330c058 100644 --- a/valuescript_vm/src/builtins/array_builtin.rs +++ b/valuescript_vm/src/builtins/array_builtin.rs @@ -6,7 +6,7 @@ use crate::{ builtins::range_error_builtin::to_range_error, builtins::type_error_builtin::to_type_error, format_err, - native_function::NativeFunction, + native_function::{NativeFunction, ThisWrapper}, operations::op_sub, range_error, type_error, vs_array::VsArray, @@ -88,7 +88,7 @@ impl ValTrait for ArrayBuiltin { } static IS_ARRAY: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { Ok(match params.get(0) { None => Val::Bool(false), Some(p) => match p.as_array_data() { @@ -100,7 +100,7 @@ static IS_ARRAY: NativeFunction = NativeFunction { }; static FROM: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let first_param = match params.get(0) { None => return type_error!("undefined is not iterable"), Some(p) => p, @@ -157,12 +157,12 @@ static FROM: NativeFunction = NativeFunction { }; static OF: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { Ok(Val::Array(Rc::new(VsArray::from(params)))) }, }; -fn to_array(_: &mut Val, params: Vec) -> Result { +fn to_array(_: ThisWrapper, params: Vec) -> Result { if params.len() != 1 { return Ok(Val::Array(Rc::new(VsArray::from(params)))); } diff --git a/valuescript_vm/src/builtins/boolean_builtin.rs b/valuescript_vm/src/builtins/boolean_builtin.rs index 6f47a12..eb95b42 100644 --- a/valuescript_vm/src/builtins/boolean_builtin.rs +++ b/valuescript_vm/src/builtins/boolean_builtin.rs @@ -4,6 +4,7 @@ use num_bigint::BigInt; use crate::{ builtins::type_error_builtin::to_type_error, + native_function::ThisWrapper, type_error, vs_array::VsArray, vs_class::VsClass, @@ -78,7 +79,7 @@ impl ValTrait for BooleanBuiltin { } } -fn to_boolean(_: &mut Val, params: Vec) -> Result { +fn to_boolean(_: ThisWrapper, params: Vec) -> Result { Ok(if let Some(value) = params.get(0) { Val::Bool(value.is_truthy()) } else { diff --git a/valuescript_vm/src/builtins/debug_builtin.rs b/valuescript_vm/src/builtins/debug_builtin.rs index e9fa8bc..75c7983 100644 --- a/valuescript_vm/src/builtins/debug_builtin.rs +++ b/valuescript_vm/src/builtins/debug_builtin.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use num_bigint::BigInt; -use crate::native_function::NativeFunction; +use crate::native_function::{NativeFunction, ThisWrapper}; use crate::vs_array::VsArray; use crate::vs_class::VsClass; use crate::vs_object::VsObject; @@ -82,7 +82,7 @@ impl ValTrait for DebugBuiltin { } static LOG: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { for p in params { println!("Debug.log: {}", p); } diff --git a/valuescript_vm/src/builtins/error_builtin.rs b/valuescript_vm/src/builtins/error_builtin.rs index 7213b7b..5011eee 100644 --- a/valuescript_vm/src/builtins/error_builtin.rs +++ b/valuescript_vm/src/builtins/error_builtin.rs @@ -2,6 +2,7 @@ use std::{collections::BTreeMap, rc::Rc}; use num_bigint::BigInt; +use crate::native_function::ThisWrapper; use crate::{builtins::type_error_builtin::to_type_error, type_error}; use crate::{ format_val, @@ -83,7 +84,7 @@ impl ValTrait for ErrorBuiltin { } } -fn to_error(_: &mut Val, params: Vec) -> Result { +fn to_error(_: ThisWrapper, params: Vec) -> Result { Ok(Val::Object(Rc::new(VsObject { string_map: BTreeMap::from([( "message".to_string(), @@ -111,21 +112,25 @@ fn make_error_prototype() -> Val { } static SET_MESSAGE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { + fn_: |mut this: ThisWrapper, params: Vec| -> Result { let message = match params.get(0) { Some(param) => param.val_to_string(), None => "".to_string(), }; - op_submov(this, format_val!("message"), format_val!("{}", message))?; + op_submov( + this.get_mut()?, + format_val!("message"), + format_val!("{}", message), + )?; Ok(Val::Undefined) }, }; static ERROR_TO_STRING: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - let message = op_sub(this.clone(), format_val!("message"))?; + fn_: |this: ThisWrapper, _params: Vec| -> Result { + let message = op_sub(this.get().clone(), format_val!("message"))?; Ok(format_val!("Error({})", message)) // TODO: Fixes needed here (and other errors) }, }; diff --git a/valuescript_vm/src/builtins/math_builtin.rs b/valuescript_vm/src/builtins/math_builtin.rs index 726ed79..356bf16 100644 --- a/valuescript_vm/src/builtins/math_builtin.rs +++ b/valuescript_vm/src/builtins/math_builtin.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use num_bigint::BigInt; -use crate::native_function::NativeFunction; +use crate::native_function::{NativeFunction, ThisWrapper}; use crate::operations::to_u32; use crate::vs_array::VsArray; use crate::vs_class::VsClass; @@ -134,49 +134,49 @@ fn param_to_number(param: Option<&Val>) -> f64 { } static ABS: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.abs())) }, }; static ACOS: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.acos())) }, }; static ACOSH: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.acosh())) }, }; static ASIN: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.asin())) }, }; static ASINH: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.sinh())) }, }; static ATAN: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.atan())) }, }; static ATAN2: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); let y = param_to_number(params.get(1)); @@ -185,77 +185,77 @@ static ATAN2: NativeFunction = NativeFunction { }; static ATANH: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.atanh())) }, }; static CBRT: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.cbrt())) }, }; static CEIL: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.ceil())) }, }; static CLZ32: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(to_u32(x).leading_zeros() as f64)) }, }; static COS: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.cos())) }, }; static COSH: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.cosh())) }, }; static EXP: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.exp())) }, }; static EXPM1: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.exp_m1())) }, }; static FLOOR: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.floor())) }, }; static FROUND: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x as f32 as f64)) }, }; static HYPOT: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); let y = param_to_number(params.get(1)); Ok(Val::Number(x.hypot(y))) @@ -263,7 +263,7 @@ static HYPOT: NativeFunction = NativeFunction { }; static IMUL: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); let y = param_to_number(params.get(1)); Ok(Val::Number((to_u32(x) * to_u32(y)) as i32 as f64)) @@ -271,35 +271,35 @@ static IMUL: NativeFunction = NativeFunction { }; static LOG: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.ln())) }, }; static LOG10: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.log10())) }, }; static LOG1P: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.ln_1p())) }, }; static LOG2: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.log2())) }, }; static MAX: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); let y = param_to_number(params.get(1)); Ok(Val::Number(x.max(y))) @@ -307,7 +307,7 @@ static MAX: NativeFunction = NativeFunction { }; static MIN: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); let y = param_to_number(params.get(1)); Ok(Val::Number(x.min(y))) @@ -315,7 +315,7 @@ static MIN: NativeFunction = NativeFunction { }; static POW: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); let y = param_to_number(params.get(1)); Ok(Val::Number(x.powf(y))) @@ -323,56 +323,56 @@ static POW: NativeFunction = NativeFunction { }; static ROUND: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.round())) }, }; static SIGN: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.signum())) }, }; static SIN: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.sin())) }, }; static SINH: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.sinh())) }, }; static SQRT: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.sqrt())) }, }; static TAN: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.tan())) }, }; static TANH: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.tanh())) }, }; static TRUNC: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let x = param_to_number(params.get(0)); Ok(Val::Number(x.trunc())) }, diff --git a/valuescript_vm/src/builtins/number_builtin.rs b/valuescript_vm/src/builtins/number_builtin.rs index 5de4c59..8d36025 100644 --- a/valuescript_vm/src/builtins/number_builtin.rs +++ b/valuescript_vm/src/builtins/number_builtin.rs @@ -2,6 +2,7 @@ use std::rc::Rc; use num_bigint::BigInt; +use crate::native_function::ThisWrapper; use crate::{builtins::type_error_builtin::to_type_error, type_error}; use crate::{ native_function::NativeFunction, @@ -95,7 +96,7 @@ impl ValTrait for NumberBuiltin { } pub static IS_FINITE: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { Ok(if let Some(value) = params.get(0) { let number = value.to_number(); Val::Bool(number.is_finite()) @@ -106,7 +107,7 @@ pub static IS_FINITE: NativeFunction = NativeFunction { }; static IS_INTEGER: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let num = match params.get(0) { Some(n) => n.to_number(), None => return Ok(Val::Bool(false)), @@ -120,7 +121,7 @@ static IS_INTEGER: NativeFunction = NativeFunction { }; pub static IS_NAN: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { Ok(if let Some(value) = params.get(0) { let number = value.to_number(); Val::Bool(number.is_nan()) @@ -131,7 +132,7 @@ pub static IS_NAN: NativeFunction = NativeFunction { }; static IS_SAFE_INTEGER: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let num = match params.get(0) { Some(n) => n.to_number(), None => return Ok(Val::Bool(false)), @@ -148,7 +149,7 @@ static IS_SAFE_INTEGER: NativeFunction = NativeFunction { }; pub static PARSE_FLOAT: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { Ok(if let Some(value) = params.get(0) { let string_value = value.val_to_string().trim().to_string(); @@ -163,7 +164,7 @@ pub static PARSE_FLOAT: NativeFunction = NativeFunction { }; pub static PARSE_INT: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { Ok(if let Some(value) = params.get(0) { let string_value = value.val_to_string().trim_start().to_string(); let radix = params.get(1).and_then(|v| v.to_index()).unwrap_or(10); @@ -196,7 +197,7 @@ pub static PARSE_INT: NativeFunction = NativeFunction { }, }; -fn to_number(_: &mut Val, params: Vec) -> Result { +fn to_number(_: ThisWrapper, params: Vec) -> Result { Ok(if let Some(value) = params.get(0) { Val::Number(value.to_number()) } else { diff --git a/valuescript_vm/src/builtins/range_error_builtin.rs b/valuescript_vm/src/builtins/range_error_builtin.rs index 45b01d6..2ddfb0a 100644 --- a/valuescript_vm/src/builtins/range_error_builtin.rs +++ b/valuescript_vm/src/builtins/range_error_builtin.rs @@ -2,6 +2,7 @@ use std::{collections::BTreeMap, rc::Rc}; use num_bigint::BigInt; +use crate::native_function::ThisWrapper; use crate::{builtins::type_error_builtin::to_type_error, type_error}; use crate::{ format_val, @@ -85,7 +86,7 @@ impl ValTrait for RangeErrorBuiltin { } } -pub fn to_range_error(_: &mut Val, params: Vec) -> Result { +pub fn to_range_error(_: ThisWrapper, params: Vec) -> Result { Ok(Val::Object(Rc::new(VsObject { string_map: BTreeMap::from([( "message".to_string(), @@ -113,21 +114,25 @@ fn make_range_error_prototype() -> Val { } static SET_MESSAGE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { + fn_: |mut this: ThisWrapper, params: Vec| -> Result { let message = match params.get(0) { Some(param) => param.val_to_string(), None => "".to_string(), }; - op_submov(this, format_val!("message"), format_val!("{}", message))?; + op_submov( + this.get_mut()?, + format_val!("message"), + format_val!("{}", message), + )?; Ok(Val::Undefined) }, }; static RANGE_ERROR_TO_STRING: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - let message = op_sub(this.clone(), format_val!("message"))?; + fn_: |this: ThisWrapper, _params: Vec| -> Result { + let message = op_sub(this.get().clone(), format_val!("message"))?; Ok(format_val!("RangeError({})", message)) }, }; @@ -135,10 +140,10 @@ static RANGE_ERROR_TO_STRING: NativeFunction = NativeFunction { #[macro_export] macro_rules! range_error { ($fmt:expr $(, $($arg:expr),*)?) => {{ - let mut this = Val::Undefined; let formatted_string = format!($fmt $(, $($arg),*)?); Err(to_range_error( - &mut this, vec![Val::String(Rc::new(formatted_string))] + ThisWrapper::new(true, &mut Val::Undefined), + vec![Val::String(Rc::new(formatted_string))], ).unwrap()) }}; } diff --git a/valuescript_vm/src/builtins/string_builtin.rs b/valuescript_vm/src/builtins/string_builtin.rs index f5376b0..9909395 100644 --- a/valuescript_vm/src/builtins/string_builtin.rs +++ b/valuescript_vm/src/builtins/string_builtin.rs @@ -2,6 +2,7 @@ use std::rc::Rc; use num_bigint::BigInt; +use crate::native_function::ThisWrapper; use crate::{builtins::range_error_builtin::to_range_error, range_error}; use crate::{builtins::type_error_builtin::to_type_error, type_error}; use crate::{ @@ -88,7 +89,7 @@ impl ValTrait for StringBuiltin { } static FROM_CODE_POINT: NativeFunction = NativeFunction { - fn_: |_this: &mut Val, params: Vec| -> Result { + fn_: |_this: ThisWrapper, params: Vec| -> Result { let mut result = String::new(); for param in params { @@ -106,7 +107,7 @@ static FROM_CODE_POINT: NativeFunction = NativeFunction { }, }; -fn to_string(_: &mut Val, params: Vec) -> Result { +fn to_string(_: ThisWrapper, params: Vec) -> Result { Ok(if let Some(value) = params.get(0) { Val::String(Rc::new(value.val_to_string())) } else { diff --git a/valuescript_vm/src/builtins/type_error_builtin.rs b/valuescript_vm/src/builtins/type_error_builtin.rs index e59b8b7..77e2b47 100644 --- a/valuescript_vm/src/builtins/type_error_builtin.rs +++ b/valuescript_vm/src/builtins/type_error_builtin.rs @@ -2,6 +2,7 @@ use std::{collections::BTreeMap, rc::Rc}; use num_bigint::BigInt; +use crate::native_function::ThisWrapper; use crate::type_error; use crate::{ format_val, @@ -85,7 +86,7 @@ impl ValTrait for TypeErrorBuiltin { } } -pub fn to_type_error(_: &mut Val, params: Vec) -> Result { +pub fn to_type_error(_: ThisWrapper, params: Vec) -> Result { Ok(Val::Object(Rc::new(VsObject { string_map: BTreeMap::from([( "message".to_string(), @@ -113,21 +114,25 @@ fn make_type_error_prototype() -> Val { } static SET_MESSAGE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { + fn_: |mut this: ThisWrapper, params: Vec| -> Result { let message = match params.get(0) { Some(param) => param.val_to_string(), None => "".to_string(), }; - op_submov(this, format_val!("message"), format_val!("{}", message))?; + op_submov( + this.get_mut()?, + format_val!("message"), + format_val!("{}", message), + )?; Ok(Val::Undefined) }, }; static TYPE_ERROR_TO_STRING: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - let message = op_sub(this.clone(), format_val!("message"))?; + fn_: |this: ThisWrapper, _params: Vec| -> Result { + let message = op_sub(this.get().clone(), format_val!("message"))?; Ok(format_val!("TypeError({})", message)) }, }; @@ -135,10 +140,10 @@ static TYPE_ERROR_TO_STRING: NativeFunction = NativeFunction { #[macro_export] macro_rules! type_error { ($fmt:expr $(, $($arg:expr),*)?) => {{ - let mut this = Val::Undefined; let formatted_string = format!($fmt $(, $($arg),*)?); Err(to_type_error( - &mut this, vec![Val::String(Rc::new(formatted_string))] + ThisWrapper::new(true, &mut Val::Undefined), + vec![Val::String(Rc::new(formatted_string))], ).unwrap()) }}; } diff --git a/valuescript_vm/src/bytecode_stack_frame.rs b/valuescript_vm/src/bytecode_stack_frame.rs index e83e57a..79c68e4 100644 --- a/valuescript_vm/src/bytecode_stack_frame.rs +++ b/valuescript_vm/src/bytecode_stack_frame.rs @@ -5,6 +5,7 @@ use valuescript_common::InstructionByte; use crate::builtins::type_error_builtin::to_type_error; use crate::bytecode_decoder::BytecodeDecoder; use crate::bytecode_decoder::BytecodeType; +use crate::native_function::ThisWrapper; use crate::operations; use crate::stack_frame::FrameStepOk; use crate::stack_frame::FrameStepResult; @@ -187,7 +188,10 @@ impl StackFrameTrait for BytecodeStackFrame { return Ok(FrameStepOk::Push(new_frame)); } LoadFunctionResult::NativeFunction(native_fn) => { - let res = native_fn(&mut Val::Undefined, self.decode_parameters())?; + let res = native_fn( + ThisWrapper::new(true, &mut Val::Undefined), + self.decode_parameters(), + )?; match self.decoder.decode_register_index() { Some(return_target) => { @@ -316,10 +320,11 @@ impl StackFrameTrait for BytecodeStackFrame { let params = self.decode_parameters(); let res = match &mut obj { - ThisArg::Register(reg_i) => { - native_fn(self.registers.get_mut(reg_i.clone()).unwrap(), params)? - } - ThisArg::Val(val) => native_fn(val, params)?, + ThisArg::Register(reg_i) => native_fn( + ThisWrapper::new(false, self.registers.get_mut(reg_i.clone()).unwrap()), + params, + )?, + ThisArg::Val(val) => native_fn(ThisWrapper::new(true, val), params)?, }; match self.decoder.decode_register_index() { @@ -389,7 +394,10 @@ impl StackFrameTrait for BytecodeStackFrame { return Ok(FrameStepOk::Push(new_frame)); } LoadFunctionResult::NativeFunction(native_fn) => { - native_fn(&mut instance, self.decode_parameters())?; + native_fn( + ThisWrapper::new(false, &mut instance), + self.decode_parameters(), + )?; match self.decoder.decode_register_index() { Some(target) => { diff --git a/valuescript_vm/src/native_frame_function.rs b/valuescript_vm/src/native_frame_function.rs index c30e936..7e71178 100644 --- a/valuescript_vm/src/native_frame_function.rs +++ b/valuescript_vm/src/native_frame_function.rs @@ -3,6 +3,7 @@ use std::rc::Rc; use num_bigint::BigInt; use crate::format_err; +use crate::native_function::ThisWrapper; use crate::stack_frame::StackFrame; use crate::vs_array::VsArray; use crate::vs_class::VsClass; diff --git a/valuescript_vm/src/native_function.rs b/valuescript_vm/src/native_function.rs index b4cf259..50ae618 100644 --- a/valuescript_vm/src/native_function.rs +++ b/valuescript_vm/src/native_function.rs @@ -9,8 +9,31 @@ use crate::vs_object::VsObject; use crate::vs_value::{LoadFunctionResult, Val, ValTrait, VsType}; use crate::{builtins::type_error_builtin::to_type_error, type_error}; +pub struct ThisWrapper<'a> { + const_: bool, + this: &'a mut Val, +} + +impl<'a> ThisWrapper<'a> { + pub fn new(const_: bool, this: &'a mut Val) -> ThisWrapper<'a> { + ThisWrapper { const_, this } + } + + pub fn get(&self) -> &Val { + self.this + } + + pub fn get_mut(&mut self) -> Result<&mut Val, Val> { + if self.const_ { + return type_error!("Cannot mutate this because it is const"); + } + + Ok(self.this) + } +} + pub struct NativeFunction { - pub fn_: fn(this: &mut Val, params: Vec) -> Result, + pub fn_: fn(this: ThisWrapper, params: Vec) -> Result, } impl ValTrait for NativeFunction { diff --git a/valuescript_vm/src/number_methods.rs b/valuescript_vm/src/number_methods.rs index 8a41fcb..eb80528 100644 --- a/valuescript_vm/src/number_methods.rs +++ b/valuescript_vm/src/number_methods.rs @@ -1,5 +1,6 @@ use std::rc::Rc; +use crate::native_function::ThisWrapper; use crate::{builtins::range_error_builtin::to_range_error, range_error}; use crate::{ format_err, format_val, @@ -21,8 +22,8 @@ pub fn op_sub_number(_number: f64, subscript: &Val) -> Val { } static TO_FIXED: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::Number(number) => { if number.is_infinite() { return Ok(if number.is_sign_positive() { @@ -34,7 +35,7 @@ static TO_FIXED: NativeFunction = NativeFunction { let mut precision = match params.get(0) { Some(p) => p.to_number(), - _ => return Ok(Val::String(Rc::new(this.val_to_string()))), + _ => return Ok(Val::String(Rc::new(this.get().val_to_string()))), }; precision = f64::floor(precision); @@ -51,8 +52,8 @@ static TO_FIXED: NativeFunction = NativeFunction { }; static TO_EXPONENTIAL: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::Number(number) => match params.get(0) { Some(p) => { let mut precision = p.to_number(); @@ -72,8 +73,8 @@ static TO_EXPONENTIAL: NativeFunction = NativeFunction { }; static TODO_LOCALE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + match this.get() { Val::Number(_number) => return format_err!("TODO: locale"), _ => return format_err!("number indirection"), } @@ -81,14 +82,14 @@ static TODO_LOCALE: NativeFunction = NativeFunction { }; static TO_STRING: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::Number(_) => match params.get(0) { Some(_) => { return format_err!("TODO: toString with radix"); } - None => Val::String(Rc::new(this.val_to_string())), + None => Val::String(Rc::new(this.get().val_to_string())), }, _ => return format_err!("number indirection"), }) @@ -96,8 +97,8 @@ static TO_STRING: NativeFunction = NativeFunction { }; static VALUE_OF: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(match this.get() { Val::Number(number) => Val::Number(*number), _ => return format_err!("number indirection"), }) diff --git a/valuescript_vm/src/operations.rs b/valuescript_vm/src/operations.rs index ea0c5bc..9818d06 100644 --- a/valuescript_vm/src/operations.rs +++ b/valuescript_vm/src/operations.rs @@ -7,6 +7,7 @@ use crate::bigint_methods::op_sub_bigint; use crate::format_err; use crate::format_val; use crate::native_function::NativeFunction; +use crate::native_function::ThisWrapper; use crate::number_methods::op_sub_number; use crate::string_methods::op_sub_string; use crate::vs_value::Val; @@ -480,8 +481,8 @@ pub fn op_submov(target: &mut Val, subscript: Val, value: Val) -> Result<(), Val } static BOOL_TO_STRING: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(match &this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(match this.get() { Val::Bool(b) => Val::String(Rc::new(b.to_string())), _ => return format_err!("bool indirection"), }) @@ -489,8 +490,8 @@ static BOOL_TO_STRING: NativeFunction = NativeFunction { }; static BOOL_VALUE_OF: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(match &this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(match this.get() { Val::Bool(b) => Val::Bool(*b), _ => return format_err!("bool indirection"), }) diff --git a/valuescript_vm/src/string_methods.rs b/valuescript_vm/src/string_methods.rs index aa4c3ff..a7d8475 100644 --- a/valuescript_vm/src/string_methods.rs +++ b/valuescript_vm/src/string_methods.rs @@ -3,7 +3,7 @@ use std::{rc::Rc, str::Chars}; use crate::{ format_err, helpers::{to_wrapping_index, to_wrapping_index_clamped}, - native_function::NativeFunction, + native_function::{NativeFunction, ThisWrapper}, vs_array::VsArray, vs_value::Val, ValTrait, @@ -85,8 +85,8 @@ pub fn get_string_method(method: &str) -> Val { } static AT: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let string_bytes = string_data.as_bytes(); @@ -106,8 +106,8 @@ static AT: NativeFunction = NativeFunction { }; static CODE_POINT_AT: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let string_bytes = string_data.as_bytes(); @@ -130,8 +130,8 @@ static CODE_POINT_AT: NativeFunction = NativeFunction { }; static CONCAT: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let mut result = string_data.as_str().to_string(); @@ -147,8 +147,8 @@ static CONCAT: NativeFunction = NativeFunction { }; static ENDS_WITH: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let string_bytes = string_data.as_bytes(); @@ -190,8 +190,8 @@ static ENDS_WITH: NativeFunction = NativeFunction { }; static INCLUDES: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let string_bytes = string_data.as_bytes(); @@ -222,8 +222,8 @@ static INCLUDES: NativeFunction = NativeFunction { }; static INDEX_OF: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let string_bytes = string_data.as_bytes(); @@ -254,8 +254,8 @@ static INDEX_OF: NativeFunction = NativeFunction { }; static LAST_INDEX_OF: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let string_bytes = string_data.as_bytes(); @@ -286,9 +286,9 @@ static LAST_INDEX_OF: NativeFunction = NativeFunction { }; static TODO_LOCALE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { + fn_: |this: ThisWrapper, _params: Vec| -> Result { // TODO: Ok(...) - match this { + match this.get() { Val::String(_string_data) => { return format_err!("TODO: locale"); } @@ -298,9 +298,9 @@ static TODO_LOCALE: NativeFunction = NativeFunction { }; static TODO_REGEXES: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { + fn_: |this: ThisWrapper, _params: Vec| -> Result { // TODO: Ok(...) - match this { + match this.get() { Val::String(_string_data) => { return format_err!("TODO: regexes"); } @@ -310,9 +310,9 @@ static TODO_REGEXES: NativeFunction = NativeFunction { }; static NORMALIZE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { + fn_: |this: ThisWrapper, _params: Vec| -> Result { // TODO: Ok(...) - match this { + match this.get() { Val::String(_string_data) => { // Consider https://docs.rs/unicode-normalization/latest/unicode_normalization/ return format_err!("TODO: normalize"); @@ -324,8 +324,8 @@ static NORMALIZE: NativeFunction = NativeFunction { // TODO: JS has some locale-specific behavior, not sure yet how we should deal with that static PAD_END: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let target_length = match params.get(0) { Some(p) => match p.to_index() { @@ -378,8 +378,8 @@ static PAD_END: NativeFunction = NativeFunction { // TODO: JS has some locale-specific behavior, not sure yet how we should deal with that static PAD_START: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let target_length = match params.get(0) { Some(p) => match p.to_index() { @@ -433,8 +433,8 @@ static PAD_START: NativeFunction = NativeFunction { }; static REPEAT: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let count = match params.get(0) { Some(p) => match p.to_index() { @@ -458,8 +458,8 @@ static REPEAT: NativeFunction = NativeFunction { }; static SLICE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let string_bytes = string_data.as_bytes(); @@ -492,8 +492,8 @@ static SLICE: NativeFunction = NativeFunction { }; static SPLIT: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let separator = match params.get(0) { Some(s) => s.val_to_string(), // TODO: Regexes @@ -558,8 +558,8 @@ static SPLIT: NativeFunction = NativeFunction { }; static STARTS_WITH: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let string_bytes = string_data.as_bytes(); @@ -599,8 +599,8 @@ static STARTS_WITH: NativeFunction = NativeFunction { }; static SUBSTRING: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let string_bytes = string_data.as_bytes(); @@ -642,8 +642,8 @@ static SUBSTRING: NativeFunction = NativeFunction { }; static TO_LOWER_CASE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let lowercased_string = string_data.to_lowercase(); Val::String(Rc::new(lowercased_string)) @@ -654,8 +654,8 @@ static TO_LOWER_CASE: NativeFunction = NativeFunction { }; static TO_STRING: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => Val::String(string_data.clone()), _ => return format_err!("string indirection"), }) @@ -663,8 +663,8 @@ static TO_STRING: NativeFunction = NativeFunction { }; static TO_UPPER_CASE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let uppercased_string = string_data.to_uppercase(); Val::String(Rc::new(uppercased_string)) @@ -675,8 +675,8 @@ static TO_UPPER_CASE: NativeFunction = NativeFunction { }; static TRIM: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let trimmed_string = string_data.trim(); Val::String(Rc::new(trimmed_string.to_owned())) @@ -687,8 +687,8 @@ static TRIM: NativeFunction = NativeFunction { }; static TRIM_END: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let trimmed_string = string_data.trim_end(); Val::String(Rc::new(trimmed_string.to_owned())) @@ -699,8 +699,8 @@ static TRIM_END: NativeFunction = NativeFunction { }; static TRIM_START: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => { let trimmed_string = string_data.trim_start(); Val::String(Rc::new(trimmed_string.to_owned())) @@ -711,8 +711,8 @@ static TRIM_START: NativeFunction = NativeFunction { }; static VALUE_OF: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(match this.get() { Val::String(string_data) => Val::String(string_data.clone()), _ => return format_err!("string indirection"), }) diff --git a/valuescript_vm/src/todo_fn.rs b/valuescript_vm/src/todo_fn.rs index d025a5c..5b04ecc 100644 --- a/valuescript_vm/src/todo_fn.rs +++ b/valuescript_vm/src/todo_fn.rs @@ -1,10 +1,14 @@ use std::rc::Rc; -use crate::{format_err, native_function::NativeFunction, vs_value::Val}; +use crate::{ + format_err, + native_function::{NativeFunction, ThisWrapper}, + vs_value::Val, +}; pub static TODO: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + match this.get() { Val::Number(_number) => return format_err!("TODO: locale"), _ => return format_err!("number indirection"), } diff --git a/valuescript_vm/src/vs_array.rs b/valuescript_vm/src/vs_array.rs index 0d4ec35..762b417 100644 --- a/valuescript_vm/src/vs_array.rs +++ b/valuescript_vm/src/vs_array.rs @@ -10,7 +10,7 @@ use crate::array_higher_functions::{ }; use crate::format_err; use crate::helpers::{to_wrapping_index, to_wrapping_index_clamped}; -use crate::native_function::NativeFunction; +use crate::native_function::{NativeFunction, ThisWrapper}; use crate::operations::op_triple_eq_impl; use crate::vs_class::VsClass; use crate::vs_object::VsObject; @@ -149,8 +149,8 @@ impl ValTrait for ArrayPrototype { } static AT: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::Array(array_data) => match to_wrapping_index(params.get(0), array_data.elements.len()) { None => Val::Undefined, Some(i) => array_data.elements[i].clone(), @@ -161,8 +161,8 @@ static AT: NativeFunction = NativeFunction { }; static CONCAT: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::Array(array_data) => { let mut new_array = array_data.as_ref().clone(); @@ -187,7 +187,9 @@ static CONCAT: NativeFunction = NativeFunction { }; static COPY_WITHIN: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { + fn_: |mut this: ThisWrapper, params: Vec| -> Result { + let this = this.get_mut()?; + Ok(match this { Val::Array(array_data) => { let array_data_mut = Rc::make_mut(array_data); @@ -259,8 +261,8 @@ static COPY_WITHIN: NativeFunction = NativeFunction { }; static ENTRIES: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - match this { + fn_: |this: ThisWrapper, _params: Vec| -> Result { + match this.get() { Val::Array(_array_data) => return format_err!("TODO: iterators"), _ => return format_err!("array indirection"), }; @@ -268,7 +270,9 @@ static ENTRIES: NativeFunction = NativeFunction { }; static FILL: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { + fn_: |mut this: ThisWrapper, params: Vec| -> Result { + let this = this.get_mut()?; + Ok(match this { Val::Array(array_data) => { let array_data_mut = Rc::make_mut(array_data); @@ -298,8 +302,8 @@ static FILL: NativeFunction = NativeFunction { }; static FLAT: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::Array(array_data) => { if params.len() > 0 { return format_err!("TODO: .flat depth parameter"); @@ -328,8 +332,8 @@ static FLAT: NativeFunction = NativeFunction { }; static INCLUDES: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::Array(array_data) => { let search_param = params.get(0).unwrap_or(&Val::Undefined).clone(); @@ -351,8 +355,8 @@ static INCLUDES: NativeFunction = NativeFunction { }; static INDEX_OF: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::Array(array_data) => { let search_param = params.get(0).unwrap_or(&Val::Undefined).clone(); @@ -374,8 +378,8 @@ static INDEX_OF: NativeFunction = NativeFunction { }; static JOIN: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::Array(vals) => { if vals.elements.len() == 0 { return Ok(Val::String(Rc::new("".to_string()))); @@ -414,9 +418,9 @@ static JOIN: NativeFunction = NativeFunction { }; static KEYS: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { + fn_: |this: ThisWrapper, _params: Vec| -> Result { // TODO: Ok(...) - match this { + match this.get() { Val::Array(_array_data) => { return format_err!("TODO: KEYS"); } @@ -426,8 +430,8 @@ static KEYS: NativeFunction = NativeFunction { }; static LAST_INDEX_OF: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::Array(array_data) => { let search_param = params.get(0).unwrap_or(&Val::Undefined).clone(); @@ -449,7 +453,9 @@ static LAST_INDEX_OF: NativeFunction = NativeFunction { }; static POP: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { + fn_: |mut this: ThisWrapper, _params: Vec| -> Result { + let this = this.get_mut()?; + Ok(match this { Val::Array(array_data) => { if array_data.elements.len() == 0 { @@ -473,7 +479,9 @@ static POP: NativeFunction = NativeFunction { }; static PUSH: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { + fn_: |mut this: ThisWrapper, params: Vec| -> Result { + let this = this.get_mut()?; + Ok(match this { Val::Array(array_data) => { let array_data_mut = Rc::make_mut(array_data); @@ -490,7 +498,9 @@ static PUSH: NativeFunction = NativeFunction { }; static REVERSE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { + fn_: |mut this: ThisWrapper, _params: Vec| -> Result { + let this = this.get_mut()?; + Ok(match this { Val::Array(array_data) => { if array_data.elements.len() == 0 { @@ -517,7 +527,9 @@ static REVERSE: NativeFunction = NativeFunction { }; static SHIFT: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { + fn_: |mut this: ThisWrapper, _params: Vec| -> Result { + let this = this.get_mut()?; + Ok(match this { Val::Array(array_data) => { if array_data.elements.len() == 0 { @@ -534,8 +546,8 @@ static SHIFT: NativeFunction = NativeFunction { }; static SLICE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { - Ok(match this { + fn_: |this: ThisWrapper, params: Vec| -> Result { + Ok(match this.get() { Val::Array(array_data) => { let mut new_elems = Vec::::new(); @@ -561,7 +573,9 @@ static SLICE: NativeFunction = NativeFunction { }; static SPLICE: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { + fn_: |mut this: ThisWrapper, params: Vec| -> Result { + let this = this.get_mut()?; + Ok(match this { Val::Array(array_data) => { let array_data_mut = Rc::make_mut(array_data); @@ -638,9 +652,9 @@ static SPLICE: NativeFunction = NativeFunction { }; static TO_LOCALE_STRING: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { + fn_: |this: ThisWrapper, _params: Vec| -> Result { // TODO: Ok(...) - match this { + match this.get() { Val::Array(_array_data) => { return format_err!("TODO: TO_LOCALE_STRING"); } @@ -651,13 +665,15 @@ static TO_LOCALE_STRING: NativeFunction = NativeFunction { // TODO: Share this? (JS doesn't?) static TO_STRING: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { - Ok(Val::String(Rc::new(this.val_to_string()))) + fn_: |this: ThisWrapper, _params: Vec| -> Result { + Ok(Val::String(Rc::new(this.get().val_to_string()))) }, }; static UNSHIFT: NativeFunction = NativeFunction { - fn_: |this: &mut Val, params: Vec| -> Result { + fn_: |mut this: ThisWrapper, params: Vec| -> Result { + let this = this.get_mut()?; + Ok(match this { Val::Array(array_data) => { let array_data_mut = Rc::make_mut(array_data); @@ -677,9 +693,9 @@ static UNSHIFT: NativeFunction = NativeFunction { }; static VALUES: NativeFunction = NativeFunction { - fn_: |this: &mut Val, _params: Vec| -> Result { + fn_: |this: ThisWrapper, _params: Vec| -> Result { // TODO: Ok(...) - match this { + match this.get() { Val::Array(_array_data) => { return format_err!("TODO: VALUES"); } diff --git a/valuescript_vm/src/vs_value.rs b/valuescript_vm/src/vs_value.rs index f32fc59..a2616a1 100644 --- a/valuescript_vm/src/vs_value.rs +++ b/valuescript_vm/src/vs_value.rs @@ -7,6 +7,7 @@ use num_traits::cast::ToPrimitive; use num_traits::Zero; use crate::format_val; +use crate::native_function::ThisWrapper; use crate::operations::{op_sub, op_submov}; use crate::stack_frame::StackFrame; use crate::vs_array::VsArray; @@ -48,7 +49,7 @@ pub enum VsType { pub enum LoadFunctionResult { NotAFunction, StackFrame(StackFrame), - NativeFunction(fn(this: &mut Val, params: Vec) -> Result), + NativeFunction(fn(this: ThisWrapper, params: Vec) -> Result), } pub trait ValTrait {