diff --git a/compile_to_rust_tests/src/main.rs b/compile_to_rust_tests/src/main.rs index d78245e..61491e7 100644 --- a/compile_to_rust_tests/src/main.rs +++ b/compile_to_rust_tests/src/main.rs @@ -3,7 +3,7 @@ use std::process::exit; use valuescript_vm::{ operations::{op_less, op_minus, op_plus}, vs_value::{ToVal, Val}, - ValTrait, + ValTrait, Vallish, }; pub fn main() { @@ -64,21 +64,22 @@ pub fn main() { // } // 1.09s +// Update: 1.06s pub fn fib(n: Val) -> Result { let mut _return = Val::Undefined; - let mut _tmp0 = op_less(n.clone(), 2.0.to_val())?; + let mut _tmp0 = op_less(Vallish::Ref(&n), Vallish::Own(2.0.to_val()))?; if _tmp0.is_truthy() { _return = n; return Ok(_return); } - let mut _tmp1 = op_minus(n.clone(), 1.0.to_val())?; + let mut _tmp1 = op_minus(Vallish::Ref(&n), Vallish::Own(1.0.to_val()))?; let mut _tmp2 = fib(_tmp1)?; - _tmp1 = op_minus(n, 2.0.to_val())?; + _tmp1 = op_minus(Vallish::Own(n), Vallish::Own(2.0.to_val()))?; let mut _tmp3 = fib(_tmp1)?; - _return = op_plus(_tmp2, _tmp3)?; + _return = op_plus(Vallish::Own(_tmp2), Vallish::Own(_tmp3))?; return Ok(_return); } diff --git a/inputs/failing/copyCounting/subscript.ts b/inputs/passing/copyCounting/subscript.ts similarity index 79% rename from inputs/failing/copyCounting/subscript.ts rename to inputs/passing/copyCounting/subscript.ts index ca31b43..f356140 100644 --- a/inputs/failing/copyCounting/subscript.ts +++ b/inputs/passing/copyCounting/subscript.ts @@ -1,5 +1,4 @@ -//! test_output(1) -// Should be: 0 +//! test_output(0) /// diff --git a/valuescript_vm/src/builtins/array_builtin.rs b/valuescript_vm/src/builtins/array_builtin.rs index 923b181..0cdd5c0 100644 --- a/valuescript_vm/src/builtins/array_builtin.rs +++ b/valuescript_vm/src/builtins/array_builtin.rs @@ -72,7 +72,7 @@ static FROM: NativeFunction = native_fn(|_this, params| { Val::Bool(..) | Val::Number(..) | Val::BigInt(..) | Val::Symbol(..) => VsArray::new().to_val(), Val::Object(..) | Val::Function(..) | Val::Class(..) | Val::Static(..) | Val::Dynamic(..) => { let len = first_param - .sub("length".to_val()) + .sub(&"length".to_val()) .map_err(|e| e.to_string()) .unwrap() // TODO: Exception .to_number(); @@ -93,7 +93,7 @@ static FROM: NativeFunction = native_fn(|_this, params| { for i in 0..len { arr.push( first_param - .sub((i as f64).to_val()) + .sub(&(i as f64).to_val()) .map_err(|e| e.to_string()) .unwrap(), // TODO: Exception ); diff --git a/valuescript_vm/src/builtins/builtin_object.rs b/valuescript_vm/src/builtins/builtin_object.rs index 963ad64..553b0bc 100644 --- a/valuescript_vm/src/builtins/builtin_object.rs +++ b/valuescript_vm/src/builtins/builtin_object.rs @@ -66,7 +66,7 @@ where Self::bo_load_function() } - fn sub(&self, key: Val) -> Result { + fn sub(&self, key: &Val) -> Result { Ok(Self::bo_sub(&key.to_string())) } diff --git a/valuescript_vm/src/builtins/error_builtin.rs b/valuescript_vm/src/builtins/error_builtin.rs index 496691a..74077d3 100644 --- a/valuescript_vm/src/builtins/error_builtin.rs +++ b/valuescript_vm/src/builtins/error_builtin.rs @@ -104,6 +104,6 @@ static SET_MESSAGE: NativeFunction = native_fn(|mut this, params| { }); static ERROR_TO_STRING: NativeFunction = native_fn(|this, _params| { - let message = this.get().sub("message".to_val())?; + let message = this.get().sub(&"message".to_val())?; Ok(format!("Error({})", message).to_val()) // TODO: Fixes needed here (and other errors) }); diff --git a/valuescript_vm/src/builtins/range_error_builtin.rs b/valuescript_vm/src/builtins/range_error_builtin.rs index 4e4205c..5f86b51 100644 --- a/valuescript_vm/src/builtins/range_error_builtin.rs +++ b/valuescript_vm/src/builtins/range_error_builtin.rs @@ -85,7 +85,7 @@ pub fn to_range_error(_: ThisWrapper, params: Vec) -> Result { } static RANGE_ERROR_TO_STRING: NativeFunction = native_fn(|this, _params| { - let message = this.get().sub("message".to_val())?; + let message = this.get().sub(&"message".to_val())?; Ok(format!("RangeError({})", message).to_val()) }); diff --git a/valuescript_vm/src/builtins/type_error_builtin.rs b/valuescript_vm/src/builtins/type_error_builtin.rs index 902371d..16fb6a7 100644 --- a/valuescript_vm/src/builtins/type_error_builtin.rs +++ b/valuescript_vm/src/builtins/type_error_builtin.rs @@ -76,7 +76,7 @@ static SET_MESSAGE: NativeFunction = native_fn(|mut this, params| { }); static TYPE_ERROR_TO_STRING: NativeFunction = native_fn(|this, _params| { - let message = this.get().sub("message".to_val())?; + let message = this.get().sub(&"message".to_val())?; Ok(format!("TypeError({})", message).to_val()) }); diff --git a/valuescript_vm/src/bytecode_decoder.rs b/valuescript_vm/src/bytecode_decoder.rs index b15d756..b99884b 100644 --- a/valuescript_vm/src/bytecode_decoder.rs +++ b/valuescript_vm/src/bytecode_decoder.rs @@ -156,7 +156,7 @@ impl BytecodeDecoder { } pub fn decode_val(&mut self, registers: &Vec) -> Val { - return self.decode_vallish(registers).get_val(); + return self.decode_vallish(registers).get_own(); } pub fn decode_vec_val(&mut self, registers: &Vec) -> Vec { @@ -315,7 +315,7 @@ pub enum Vallish<'a> { } impl<'a> Vallish<'a> { - pub fn get_val(self) -> Val { + pub fn get_own(self) -> Val { match self { Vallish::Own(val) => val, Vallish::Ref(val) => val.clone(), diff --git a/valuescript_vm/src/bytecode_stack_frame.rs b/valuescript_vm/src/bytecode_stack_frame.rs index c15c1a3..0b94ca4 100644 --- a/valuescript_vm/src/bytecode_stack_frame.rs +++ b/valuescript_vm/src/bytecode_stack_frame.rs @@ -3,6 +3,7 @@ use valuescript_common::InstructionByte; use crate::builtins::type_error_builtin::ToTypeError; use crate::bytecode_decoder::BytecodeDecoder; use crate::bytecode_decoder::BytecodeType; +use crate::bytecode_decoder::Vallish; use crate::cat_stack_frame::CatStackFrame; use crate::native_function::ThisWrapper; use crate::operations; @@ -44,10 +45,10 @@ impl BytecodeStackFrame { pub fn apply_binary_op( &mut self, - op: fn(left: Val, right: Val) -> Result, + op: fn(left: Vallish, right: Vallish) -> Result, ) -> Result<(), Val> { - let left = self.decoder.decode_val(&self.registers); - let right = self.decoder.decode_val(&self.registers); + let left = self.decoder.decode_vallish(&self.registers); + let right = self.decoder.decode_vallish(&self.registers); let register_index = self.decoder.decode_register_index(); @@ -150,28 +151,24 @@ impl StackFrameTrait for BytecodeStackFrame { OpInc => { let register_index = self.decoder.decode_register_index().unwrap(); - let mut val = self.registers[register_index].clone(); + let val = &mut self.registers[register_index]; - match &mut val { + match val { Val::Number(n) => *n += 1.0, Val::BigInt(bi) => *bi += 1, - _ => val = operations::op_plus(val, 1.0.to_val())?, + _ => *val = operations::op_plus(Vallish::Ref(val), Vallish::Own(1.0.to_val()))?, }; - - self.registers[register_index] = val; } OpDec => { let register_index = self.decoder.decode_register_index().unwrap(); - let mut val = self.registers[register_index].clone(); + let val = &mut self.registers[register_index]; - match &mut val { + match val { Val::Number(n) => *n -= 1.0, Val::BigInt(bi) => *bi -= 1, - _ => val = operations::op_minus(val, 1.0.to_val())?, + _ => *val = operations::op_minus(Vallish::Ref(val), Vallish::Own(1.0.to_val()))?, }; - - self.registers[register_index] = val; } OpPlus => self.apply_binary_op(operations::op_plus)?, @@ -326,11 +323,11 @@ impl StackFrameTrait for BytecodeStackFrame { _ => ThisArg::Val(self.decoder.decode_val(&self.registers)), }; - let subscript = self.decoder.decode_val(&self.registers); + let subscript = self.decoder.decode_vallish(&self.registers); let fn_ = match &obj { - ThisArg::Register(reg_i) => self.registers[reg_i.clone()].sub(subscript)?, - ThisArg::Val(val) => val.sub(subscript)?, + ThisArg::Register(reg_i) => self.registers[reg_i.clone()].sub(subscript.get_ref())?, + ThisArg::Val(val) => val.sub(subscript.get_ref())?, }; match fn_.load_function() { @@ -499,7 +496,7 @@ impl StackFrameTrait for BytecodeStackFrame { let res_i = self.decoder.decode_register_index(); - let next_fn = self.registers[iter_i].sub("next".to_val())?; + let next_fn = self.registers[iter_i].sub(&"next".to_val())?; match next_fn.load_function() { LoadFunctionResult::NotAFunction => { @@ -530,11 +527,11 @@ impl StackFrameTrait for BytecodeStackFrame { }; if let Some(value_i) = self.decoder.decode_register_index() { - self.registers[value_i] = self.registers[iter_res_i].sub("value".to_val())?; + self.registers[value_i] = self.registers[iter_res_i].sub(&"value".to_val())?; } if let Some(done_i) = self.decoder.decode_register_index() { - self.registers[done_i] = self.registers[iter_res_i].sub("done".to_val())?; + self.registers[done_i] = self.registers[iter_res_i].sub(&"done".to_val())?; } } diff --git a/valuescript_vm/src/cat_stack_frame.rs b/valuescript_vm/src/cat_stack_frame.rs index 6c02a7f..cc52d2c 100644 --- a/valuescript_vm/src/cat_stack_frame.rs +++ b/valuescript_vm/src/cat_stack_frame.rs @@ -2,6 +2,7 @@ use std::{mem::take, rc::Rc}; use crate::{ builtins::type_error_builtin::ToTypeError, + bytecode_decoder::Vallish, native_function::ThisWrapper, operations::op_sub, stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrame, StackFrameTrait}, @@ -63,7 +64,10 @@ impl CatStackFrame { return Ok(FrameStepOk::Continue); } - let make_iter = op_sub(arg.clone(), VsSymbol::ITERATOR.to_val())?; + let make_iter = op_sub( + Vallish::Ref(&arg), + Vallish::Own(VsSymbol::ITERATOR.to_val()), + )?; match make_iter.load_function() { LoadFunctionResult::NotAFunction => Err("Non-iterable cat argument".to_type_error()), @@ -84,12 +88,12 @@ impl CatStackFrame { res: &mut Vec, iter_result: Val, ) -> Result<(), Val> { - let done = iter_result.sub("done".to_val())?.is_truthy(); + let done = iter_result.sub(&"done".to_val())?.is_truthy(); if done { *state = CatFrameState::ReadNext; } else { - res.push(iter_result.sub("value".to_val())?); + res.push(iter_result.sub(&"value".to_val())?); } Ok(()) @@ -113,7 +117,7 @@ impl StackFrameTrait for CatStackFrame { match &mut self.state { CatFrameState::ReadNext => self.read_next(), CatFrameState::MakingIterator => panic!("Unexpected step during MakingIterator"), - CatFrameState::Iterating(iter) => match iter.sub("next".to_val())?.load_function() { + CatFrameState::Iterating(iter) => match iter.sub(&"next".to_val())?.load_function() { LoadFunctionResult::NotAFunction => Err(".next was not a function".to_type_error()), LoadFunctionResult::NativeFunction(fn_) => { let iter_result = fn_(ThisWrapper::new(false, iter), vec![])?; diff --git a/valuescript_vm/src/generator.rs b/valuescript_vm/src/generator.rs index d4193de..cf11f9c 100644 --- a/valuescript_vm/src/generator.rs +++ b/valuescript_vm/src/generator.rs @@ -76,7 +76,7 @@ impl ValTrait for Generator { LoadFunctionResult::NotAFunction } - fn sub(&self, key: Val) -> Result { + 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()); diff --git a/valuescript_vm/src/iteration/array_entries_iterator.rs b/valuescript_vm/src/iteration/array_entries_iterator.rs index fc93e12..d2dab08 100644 --- a/valuescript_vm/src/iteration/array_entries_iterator.rs +++ b/valuescript_vm/src/iteration/array_entries_iterator.rs @@ -71,7 +71,7 @@ impl ValTrait for ArrayEntriesIterator { LoadFunctionResult::NotAFunction } - fn sub(&self, key: Val) -> Result { + fn sub(&self, key: &Val) -> Result { if key.to_string() == "next" { return Ok(NEXT.to_val()); } diff --git a/valuescript_vm/src/iteration/array_iterator.rs b/valuescript_vm/src/iteration/array_iterator.rs index c0047d5..c388cd5 100644 --- a/valuescript_vm/src/iteration/array_iterator.rs +++ b/valuescript_vm/src/iteration/array_iterator.rs @@ -71,7 +71,7 @@ impl ValTrait for ArrayIterator { LoadFunctionResult::NotAFunction } - fn sub(&self, key: Val) -> Result { + fn sub(&self, key: &Val) -> Result { if key.to_string() == "next" { return Ok(NEXT.to_val()); } diff --git a/valuescript_vm/src/iteration/iteration_result.rs b/valuescript_vm/src/iteration/iteration_result.rs index 0348162..30cea2b 100644 --- a/valuescript_vm/src/iteration/iteration_result.rs +++ b/valuescript_vm/src/iteration/iteration_result.rs @@ -61,7 +61,7 @@ impl ValTrait for IterationResult { LoadFunctionResult::NotAFunction } - fn sub(&self, key: Val) -> Result { + fn sub(&self, key: &Val) -> Result { Ok(match key.to_string().as_str() { "value" => self.value.clone(), "done" => self.done.to_val(), diff --git a/valuescript_vm/src/iteration/string_iterator.rs b/valuescript_vm/src/iteration/string_iterator.rs index 78e59a3..4f63c34 100644 --- a/valuescript_vm/src/iteration/string_iterator.rs +++ b/valuescript_vm/src/iteration/string_iterator.rs @@ -107,7 +107,7 @@ impl ValTrait for StringIterator { LoadFunctionResult::NotAFunction } - fn sub(&self, key: Val) -> Result { + fn sub(&self, key: &Val) -> Result { if key.to_string() == "next" { return Ok(NEXT.to_val()); } diff --git a/valuescript_vm/src/lib.rs b/valuescript_vm/src/lib.rs index ff7809d..ae5e3dd 100644 --- a/valuescript_vm/src/lib.rs +++ b/valuescript_vm/src/lib.rs @@ -27,5 +27,6 @@ mod vs_symbol; pub mod vs_value; pub use bytecode::Bytecode; +pub use bytecode_decoder::Vallish; pub use virtual_machine::VirtualMachine; pub use vs_value::{LoadFunctionResult, ValTrait}; diff --git a/valuescript_vm/src/native_frame_function.rs b/valuescript_vm/src/native_frame_function.rs index bd4e8e0..a3040e8 100644 --- a/valuescript_vm/src/native_frame_function.rs +++ b/valuescript_vm/src/native_frame_function.rs @@ -59,7 +59,7 @@ impl ValTrait for NativeFrameFunction { LoadFunctionResult::StackFrame((self.make_frame)()) } - fn sub(&self, _key: Val) -> Result { + fn sub(&self, _key: &Val) -> Result { Err("TODO: Subscript native function".to_error()) } diff --git a/valuescript_vm/src/native_function.rs b/valuescript_vm/src/native_function.rs index bd49950..840cc72 100644 --- a/valuescript_vm/src/native_function.rs +++ b/valuescript_vm/src/native_function.rs @@ -80,7 +80,7 @@ impl ValTrait for NativeFunction { LoadFunctionResult::NativeFunction(self.fn_) } - fn sub(&self, _key: Val) -> Result { + fn sub(&self, _key: &Val) -> Result { Err("TODO: Subscript native function".to_error()) } diff --git a/valuescript_vm/src/operations.rs b/valuescript_vm/src/operations.rs index 3e78af4..99f127c 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::builtins::error_builtin::ToError; use crate::builtins::range_error_builtin::ToRangeError; use crate::builtins::type_error_builtin::ToTypeError; +use crate::bytecode_decoder::Vallish; use crate::native_function::native_fn; use crate::native_function::NativeFunction; use crate::number_methods::op_sub_number; @@ -16,9 +17,9 @@ use crate::vs_value::Val; use crate::vs_value::ValTrait; use crate::vs_value::VsType; -pub fn op_plus(left: Val, right: Val) -> Result { - let left_prim = left.to_primitive(); - let right_prim = right.to_primitive(); +pub fn op_plus(left: Vallish, right: Vallish) -> Result { + let left_prim = left.get_ref().to_primitive(); + let right_prim = right.get_ref().to_primitive(); let left_type = left_prim.typeof_(); let right_type = right_prim.typeof_(); @@ -50,13 +51,16 @@ pub fn op_unary_plus(input: &Val) -> Val { } } -pub fn op_minus(left: Val, right: Val) -> Result { - match (left.as_bigint_data(), right.as_bigint_data()) { +pub fn op_minus(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + match (left_ref.as_bigint_data(), right_ref.as_bigint_data()) { (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint - right_bigint)), (Some(_), None) | (None, Some(_)) => { return Err("Cannot mix BigInt with other types".to_type_error()) } - _ => Ok(Val::Number(left.to_number() - right.to_number())), + _ => Ok(Val::Number(left_ref.to_number() - right_ref.to_number())), } } @@ -67,32 +71,44 @@ pub fn op_unary_minus(input: &Val) -> Val { } } -pub fn op_mul(left: Val, right: Val) -> Result { - match (left.as_bigint_data(), right.as_bigint_data()) { +pub fn op_mul(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + match (left_ref.as_bigint_data(), right_ref.as_bigint_data()) { (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint * right_bigint)), (Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()), - _ => Ok(Val::Number(left.to_number() * right.to_number())), + _ => Ok(Val::Number(left_ref.to_number() * right_ref.to_number())), } } -pub fn op_div(left: Val, right: Val) -> Result { - match (left.as_bigint_data(), right.as_bigint_data()) { +pub fn op_div(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + match (left_ref.as_bigint_data(), right_ref.as_bigint_data()) { (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint / right_bigint)), (Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()), - _ => Ok(Val::Number(left.to_number() / right.to_number())), + _ => Ok(Val::Number(left_ref.to_number() / right_ref.to_number())), } } -pub fn op_mod(left: Val, right: Val) -> Result { - match (left.as_bigint_data(), right.as_bigint_data()) { +pub fn op_mod(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + match (left_ref.as_bigint_data(), right_ref.as_bigint_data()) { (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint % right_bigint)), (Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()), - _ => Ok(Val::Number(left.to_number() % right.to_number())), + _ => Ok(Val::Number(left_ref.to_number() % right_ref.to_number())), } } -pub fn op_exp(left: Val, right: Val) -> Result { - match (left.as_bigint_data(), right.as_bigint_data()) { +pub fn op_exp(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + match (left_ref.as_bigint_data(), right_ref.as_bigint_data()) { (Some(left_bigint), Some(right_bigint)) => { if right_bigint.sign() == Sign::Minus { return Err("Exponent must be non-negative".to_range_error()); @@ -106,12 +122,14 @@ pub fn op_exp(left: Val, right: Val) -> Result { Ok(Val::BigInt(left_bigint.pow(exp))) } (Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()), - _ => Ok(Val::Number(left.to_number().powf(right.to_number()))), + _ => Ok(Val::Number( + left_ref.to_number().powf(right_ref.to_number()), + )), } } -pub fn op_eq(left: Val, right: Val) -> Result { - Ok(Val::Bool(match (left, right) { +pub fn op_eq(left: Vallish, right: Vallish) -> Result { + Ok(Val::Bool(match (left.get_ref(), right.get_ref()) { (Val::Undefined, Val::Undefined) => true, (Val::Null, Val::Null) => true, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool == right_bool, @@ -122,8 +140,8 @@ pub fn op_eq(left: Val, right: Val) -> Result { })) } -pub fn op_ne(left: Val, right: Val) -> Result { - Ok(Val::Bool(match (left, right) { +pub fn op_ne(left: Vallish, right: Vallish) -> Result { + Ok(Val::Bool(match (left.get_ref(), right.get_ref()) { (Val::Undefined, Val::Undefined) => false, (Val::Null, Val::Null) => false, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool != right_bool, @@ -134,8 +152,11 @@ pub fn op_ne(left: Val, right: Val) -> Result { })) } -pub fn op_triple_eq_impl(left: Val, right: Val) -> Result { - Ok(match (&left, &right) { +pub fn op_triple_eq_impl(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + Ok(match (left_ref, right_ref) { (Val::Undefined, Val::Undefined) => true, (Val::Null, Val::Null) => true, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool == right_bool, @@ -143,7 +164,7 @@ pub fn op_triple_eq_impl(left: Val, right: Val) -> Result { (Val::String(left_string), Val::String(right_string)) => left_string == right_string, (Val::BigInt(left_bigint), Val::BigInt(right_bigint)) => left_bigint == right_bigint, _ => { - if left.typeof_() != right.typeof_() { + if left_ref.typeof_() != right_ref.typeof_() { false } else { return Err("TODO".to_error()); @@ -152,30 +173,37 @@ pub fn op_triple_eq_impl(left: Val, right: Val) -> Result { }) } -pub fn op_triple_eq(left: Val, right: Val) -> Result { +pub fn op_triple_eq(left: Vallish, right: Vallish) -> Result { let is_eq = op_triple_eq_impl(left, right)?; Ok(Val::Bool(is_eq)) } -pub fn op_triple_ne(left: Val, right: Val) -> Result { +pub fn op_triple_ne(left: Vallish, right: Vallish) -> Result { let is_eq = op_triple_eq_impl(left, right)?; Ok(Val::Bool(!is_eq)) } -pub fn op_and(left: Val, right: Val) -> Result { - Ok(if left.is_truthy() { right } else { left }) +pub fn op_and(left: Vallish, right: Vallish) -> Result { + let truthy = left.get_ref().is_truthy(); + + Ok((if truthy { right } else { left }).get_own()) } -pub fn op_or(left: Val, right: Val) -> Result { - Ok(if left.is_truthy() { left } else { right }) +pub fn op_or(left: Vallish, right: Vallish) -> Result { + let truthy = left.get_ref().is_truthy(); + + Ok((if truthy { left } else { right }).get_own()) } pub fn op_not(input: &Val) -> Val { return Val::Bool(!input.is_truthy()); } -pub fn op_less(left: Val, right: Val) -> Result { - Ok(Val::Bool(match (&left, &right) { +pub fn op_less(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + Ok(Val::Bool(match (left_ref, right_ref) { (Val::Undefined, Val::Undefined) => false, (Val::Null, Val::Null) => false, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool < right_bool, @@ -183,7 +211,7 @@ pub fn op_less(left: Val, right: Val) -> Result { (Val::String(left_string), Val::String(right_string)) => left_string < right_string, (Val::BigInt(left_bigint), Val::BigInt(right_bigint)) => left_bigint < right_bigint, _ => { - if left.typeof_() == VsType::Undefined || right.typeof_() == VsType::Undefined { + if left_ref.typeof_() == VsType::Undefined || right_ref.typeof_() == VsType::Undefined { false } else { return Err("TODO".to_error()); @@ -192,8 +220,8 @@ pub fn op_less(left: Val, right: Val) -> Result { })) } -pub fn op_less_eq(left: Val, right: Val) -> Result { - Ok(Val::Bool(match (left, right) { +pub fn op_less_eq(left: Vallish, right: Vallish) -> Result { + Ok(Val::Bool(match (left.get_ref(), right.get_ref()) { (Val::Undefined, Val::Undefined) => false, (Val::Null, Val::Null) => true, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool <= right_bool, @@ -204,8 +232,8 @@ pub fn op_less_eq(left: Val, right: Val) -> Result { })) } -pub fn op_greater(left: Val, right: Val) -> Result { - Ok(Val::Bool(match (left, right) { +pub fn op_greater(left: Vallish, right: Vallish) -> Result { + Ok(Val::Bool(match (left.get_ref(), right.get_ref()) { (Val::Undefined, Val::Undefined) => false, (Val::Null, Val::Null) => false, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool > right_bool, @@ -216,8 +244,8 @@ pub fn op_greater(left: Val, right: Val) -> Result { })) } -pub fn op_greater_eq(left: Val, right: Val) -> Result { - Ok(Val::Bool(match (left, right) { +pub fn op_greater_eq(left: Vallish, right: Vallish) -> Result { + Ok(Val::Bool(match (left.get_ref(), right.get_ref()) { (Val::Undefined, Val::Undefined) => false, (Val::Null, Val::Null) => true, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool >= right_bool, @@ -228,12 +256,14 @@ pub fn op_greater_eq(left: Val, right: Val) -> Result { })) } -pub fn op_nullish_coalesce(left: Val, right: Val) -> Result { - Ok(if left.is_nullish() { right } else { left }) +pub fn op_nullish_coalesce(left: Vallish, right: Vallish) -> Result { + let nullish = left.get_ref().is_nullish(); + + Ok((if nullish { right } else { left }).get_own()) } -pub fn op_optional_chain(left: Val, right: Val) -> Result { - return match left { +pub fn op_optional_chain(left: Vallish, right: Vallish) -> Result { + return match left.get_ref() { Val::Undefined | Val::Null => Ok(Val::Undefined), _ => op_sub(left, right), @@ -260,23 +290,29 @@ pub fn to_u32(x: f64) -> u32 { return int1 as u32; } -pub fn op_bit_and(left: Val, right: Val) -> Result { - match (left.as_bigint_data(), right.as_bigint_data()) { +pub fn op_bit_and(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + match (left_ref.as_bigint_data(), right_ref.as_bigint_data()) { (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint & right_bigint)), (Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()), _ => { - let res_i32 = to_i32(left.to_number()) & to_i32(right.to_number()); + let res_i32 = to_i32(left_ref.to_number()) & to_i32(right_ref.to_number()); Ok(Val::Number(res_i32 as f64)) } } } -pub fn op_bit_or(left: Val, right: Val) -> Result { - match (left.as_bigint_data(), right.as_bigint_data()) { +pub fn op_bit_or(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + match (left_ref.as_bigint_data(), right_ref.as_bigint_data()) { (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint | right_bigint)), (Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()), _ => { - let res_i32 = to_i32(left.to_number()) | to_i32(right.to_number()); + let res_i32 = to_i32(left_ref.to_number()) | to_i32(right_ref.to_number()); Ok(Val::Number(res_i32 as f64)) } } @@ -292,50 +328,62 @@ pub fn op_bit_not(input: &Val) -> Val { } } -pub fn op_bit_xor(left: Val, right: Val) -> Result { - match (left.as_bigint_data(), right.as_bigint_data()) { +pub fn op_bit_xor(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + match (left_ref.as_bigint_data(), right_ref.as_bigint_data()) { (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint ^ right_bigint)), (Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()), _ => { - let res_i32 = to_i32(left.to_number()) ^ to_i32(right.to_number()); + let res_i32 = to_i32(left_ref.to_number()) ^ to_i32(right_ref.to_number()); Ok(Val::Number(res_i32 as f64)) } } } -pub fn op_left_shift(left: Val, right: Val) -> Result { - match (left.as_bigint_data(), right.as_bigint_data()) { +pub fn op_left_shift(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + match (left_ref.as_bigint_data(), right_ref.as_bigint_data()) { (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt( left_bigint << right_bigint.to_i64().expect("TODO"), )), (Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()), _ => { - let res_i32 = to_i32(left.to_number()) << (to_u32(right.to_number()) & 0x1f); + let res_i32 = to_i32(left_ref.to_number()) << (to_u32(right_ref.to_number()) & 0x1f); Ok(Val::Number(res_i32 as f64)) } } } -pub fn op_right_shift(left: Val, right: Val) -> Result { - match (left.as_bigint_data(), right.as_bigint_data()) { +pub fn op_right_shift(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + match (left_ref.as_bigint_data(), right_ref.as_bigint_data()) { (Some(left_bigint), Some(right_bigint)) => { let right_i64 = right_bigint.to_i64().ok_or("TODO".to_val())?; Ok(Val::BigInt(left_bigint >> right_i64)) } (Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()), _ => { - let res_i32 = to_i32(left.to_number()) >> (to_u32(right.to_number()) & 0x1f); + let res_i32 = to_i32(left_ref.to_number()) >> (to_u32(right_ref.to_number()) & 0x1f); Ok(Val::Number(res_i32 as f64)) } } } -pub fn op_right_shift_unsigned(left: Val, right: Val) -> Result { - match (left.as_bigint_data(), right.as_bigint_data()) { +pub fn op_right_shift_unsigned(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); + let right_ref = right.get_ref(); + + match (left_ref.as_bigint_data(), right_ref.as_bigint_data()) { (Some(_), Some(_)) => Err("BigInts don't support unsigned right shift".to_type_error()), (Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()), _ => { - let res_u32 = to_u32(left.to_number()) >> (to_u32(right.to_number()) & 0x1f); + let res_u32 = to_u32(left_ref.to_number()) >> (to_u32(right_ref.to_number()) & 0x1f); Ok(Val::Number(res_u32 as f64)) } } @@ -360,38 +408,41 @@ pub fn op_typeof(input: &Val) -> Val { .to_val() } -pub fn op_instance_of(_left: Val, _right: Val) -> Result { +pub fn op_instance_of(_left: Vallish, _right: Vallish) -> Result { Err("TODO: op_instance_of".to_error()) } -pub fn op_in(_left: Val, _right: Val) -> Result { +pub fn op_in(_left: Vallish, _right: Vallish) -> Result { Err("TODO: op_in".to_error()) } -pub fn op_sub(left: Val, right: Val) -> Result { - match left { +pub fn op_sub(left: Vallish, right: Vallish) -> Result { + let left_ref = left.get_ref(); // TODO: Specialize on Vallish::Own (esp array, object) + let right_ref = right.get_ref(); + + match left_ref { Val::Void => Err("Internal: Shouldn't happen".to_error()), // TODO: Internal errors Val::Undefined => Err("Cannot subscript undefined".to_type_error()), Val::Null => Err("Cannot subscript null".to_type_error()), - Val::Bool(_) => Ok(match right.to_string().as_str() { + Val::Bool(_) => Ok(match right_ref.to_string().as_str() { "toString" => BOOL_TO_STRING.to_val(), "valueOf" => BOOL_VALUE_OF.to_val(), _ => Val::Undefined, }), - Val::Number(number) => Ok(op_sub_number(number, &right)), - Val::BigInt(bigint) => Ok(op_sub_bigint(&bigint, &right)), + Val::Number(number) => Ok(op_sub_number(*number, right_ref)), + Val::BigInt(bigint) => Ok(op_sub_bigint(bigint, right_ref)), Val::Symbol(_) => Ok(Val::Undefined), - Val::String(string_data) => Ok(op_sub_string(&string_data, &right)), + Val::String(string_data) => Ok(op_sub_string(string_data, right_ref)), Val::Array(array_data) => { - let right_index = match right.to_index() { + let right_index = match right_ref.to_index() { None => { // FIXME: Inefficient to_string() that gets duplicated // when subscripting the object - if right.to_string() == "length" { + if right_ref.to_string() == "length" { return Ok(Val::Number(array_data.elements.len() as f64)); } - return Ok(array_data.object.sub(right)); + return Ok(array_data.object.sub(right_ref)); } Some(i) => i, }; @@ -407,12 +458,12 @@ pub fn op_sub(left: Val, right: Val) -> Result { _ => res, }); } - Val::Object(object_data) => Ok(object_data.sub(right)), + Val::Object(object_data) => Ok(object_data.sub(right_ref)), Val::Function(_) | Val::Class(_) => Ok(Val::Undefined), - Val::Static(s) => s.sub(right), - Val::Dynamic(dynamic_data) => dynamic_data.sub(right), - Val::CopyCounter(cc) => Ok(match right.to_string().as_str() { - "tag" => cc.tag, + Val::Static(s) => s.sub(right_ref), + Val::Dynamic(dynamic_data) => dynamic_data.sub(right_ref), + Val::CopyCounter(cc) => Ok(match right_ref.to_string().as_str() { + "tag" => cc.tag.clone(), "count" => (*cc.count.borrow() as f64).to_val(), _ => Val::Undefined, }), diff --git a/valuescript_vm/src/vs_array.rs b/valuescript_vm/src/vs_array.rs index 6ac824d..1d74fa7 100644 --- a/valuescript_vm/src/vs_array.rs +++ b/valuescript_vm/src/vs_array.rs @@ -11,6 +11,7 @@ use crate::array_higher_functions::{ }; use crate::builtins::error_builtin::ToError; use crate::builtins::type_error_builtin::ToTypeError; +use crate::bytecode_decoder::Vallish; use crate::helpers::{to_wrapping_index, to_wrapping_index_clamped}; use crate::iteration::array_entries_iterator::ArrayEntriesIterator; use crate::iteration::array_iterator::ArrayIterator; @@ -101,7 +102,7 @@ impl ValTrait for ArrayPrototype { LoadFunctionResult::NotAFunction } - fn sub(&self, key: Val) -> Result { + fn sub(&self, key: &Val) -> Result { if let Val::Symbol(symbol) = key { return Ok( match symbol { @@ -339,10 +340,10 @@ static FLAT: NativeFunction = native_fn(|this, params| { static INCLUDES: NativeFunction = native_fn(|this, params| { Ok(match this.get() { Val::Array(array_data) => { - let search_param = params.get(0).unwrap_or(&Val::Undefined).clone(); + let search_param = params.get(0).unwrap_or(&Val::Undefined); for elem in &array_data.elements { - let is_eq = op_triple_eq_impl(elem.clone(), search_param.clone()) + let is_eq = op_triple_eq_impl(Vallish::Ref(elem), Vallish::Ref(search_param)) .map_err(|e| e.to_string()) .unwrap(); // TODO: Exception @@ -360,12 +361,15 @@ static INCLUDES: NativeFunction = native_fn(|this, params| { static INDEX_OF: NativeFunction = native_fn(|this, params| { Ok(match this.get() { Val::Array(array_data) => { - let search_param = params.get(0).unwrap_or(&Val::Undefined).clone(); + let search_param = params.get(0).unwrap_or(&Val::Undefined); for i in 0..array_data.elements.len() { - let is_eq = op_triple_eq_impl(array_data.elements[i].clone(), search_param.clone()) - .map_err(|e| e.to_string()) - .unwrap(); // TODO: Exception + let is_eq = op_triple_eq_impl( + Vallish::Ref(&array_data.elements[i]), + Vallish::Ref(search_param), + ) + .map_err(|e| e.to_string()) + .unwrap(); // TODO: Exception if is_eq { return Ok(Val::Number(i as f64)); @@ -417,12 +421,15 @@ static JOIN: NativeFunction = native_fn(|this, params| { static LAST_INDEX_OF: NativeFunction = native_fn(|this, params| { Ok(match this.get() { Val::Array(array_data) => { - let search_param = params.get(0).unwrap_or(&Val::Undefined).clone(); + let search_param = params.get(0).unwrap_or(&Val::Undefined); for i in (0..array_data.elements.len()).rev() { - let is_eq = op_triple_eq_impl(array_data.elements[i].clone(), search_param.clone()) - .map_err(|e| e.to_string()) - .unwrap(); // TODO: Exception + let is_eq = op_triple_eq_impl( + Vallish::Ref(&array_data.elements[i]), + Vallish::Ref(search_param), + ) + .map_err(|e| e.to_string()) + .unwrap(); // TODO: Exception if is_eq { return Ok(Val::Number(i as f64)); diff --git a/valuescript_vm/src/vs_object.rs b/valuescript_vm/src/vs_object.rs index 68c7297..ed431a5 100644 --- a/valuescript_vm/src/vs_object.rs +++ b/valuescript_vm/src/vs_object.rs @@ -15,7 +15,7 @@ pub struct VsObject { } impl VsObject { - pub fn sub(&self, key: Val) -> Val { + pub fn sub(&self, key: &Val) -> Val { let val = match &key { Val::String(string) => self.string_map.get(&**string), Val::Symbol(symbol) => self.symbol_map.get(symbol), diff --git a/valuescript_vm/src/vs_value.rs b/valuescript_vm/src/vs_value.rs index 81f171a..d2b683f 100644 --- a/valuescript_vm/src/vs_value.rs +++ b/valuescript_vm/src/vs_value.rs @@ -7,6 +7,7 @@ use num_bigint::BigInt; use num_traits::cast::ToPrimitive; use num_traits::Zero; +use crate::bytecode_decoder::Vallish; use crate::copy_counter::CopyCounter; use crate::native_function::ThisWrapper; use crate::operations::{op_sub, op_submov}; @@ -79,7 +80,7 @@ pub trait ValTrait: fmt::Display { fn load_function(&self) -> LoadFunctionResult; - fn sub(&self, key: Val) -> Result; + fn sub(&self, key: &Val) -> Result; fn submov(&mut self, key: Val, value: Val) -> Result<(), Val>; fn pretty_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result; @@ -302,6 +303,7 @@ impl ValTrait for Val { }; } + // TODO: &BigInt ? fn as_bigint_data(&self) -> Option { use Val::*; @@ -349,9 +351,9 @@ impl ValTrait for Val { }; } - fn sub(&self, key: Val) -> Result { - // TODO: Avoid cloning? - op_sub(self.clone(), key) + fn sub(&self, key: &Val) -> Result { + // TODO: Avoid indirection? + op_sub(Vallish::Ref(self), Vallish::Ref(key)) } fn submov(&mut self, key: Val, value: Val) -> Result<(), Val> { @@ -396,7 +398,7 @@ impl ValTrait for Val { let mut res = String::new(); if let Some(proto) = &object.prototype { - match proto.sub("name".to_val()) { + match proto.sub(&"name".to_val()) { Ok(name) => { if name.typeof_() == VsType::String { res += &name.to_string(); @@ -626,7 +628,7 @@ impl<'a> std::fmt::Display for PrettyVal<'a> { } Val::Object(object) => { if let Some(proto) = &object.prototype { - match proto.sub("name".to_val()) { + match proto.sub(&"name".to_val()) { Ok(name) => { if name.typeof_() == VsType::String { write!(f, "{} ", name)?;