From b33ef2b5b06ec4deebc84441b832a86104128f47 Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Wed, 21 Jun 2023 17:16:03 +1000 Subject: [PATCH] Remove Vallish, use refs and clones --- compile_to_rust_tests/src/main.rs | 11 +- inputs/failing/copyCounting/arrayRef.ts | 2 +- inputs/failing/copyCounting/arraySwap.ts | 2 +- .../copyCounting/return.ts | 3 +- .../copyCounting/subscript.ts | 3 +- .../copyCounting/subscriptAssignment.ts | 3 +- valuescript_vm/src/bytecode_decoder.rs | 87 ++++--- valuescript_vm/src/bytecode_stack_frame.rs | 45 ++-- valuescript_vm/src/cat_stack_frame.rs | 6 +- valuescript_vm/src/lib.rs | 2 - valuescript_vm/src/operations.rs | 213 +++++++----------- valuescript_vm/src/vallish.rs | 22 -- valuescript_vm/src/vs_array.rs | 21 +- valuescript_vm/src/vs_value.rs | 5 +- 14 files changed, 177 insertions(+), 248 deletions(-) rename inputs/{passing => failing}/copyCounting/return.ts (83%) rename inputs/{passing => failing}/copyCounting/subscript.ts (79%) rename inputs/{passing => failing}/copyCounting/subscriptAssignment.ts (90%) delete mode 100644 valuescript_vm/src/vallish.rs diff --git a/compile_to_rust_tests/src/main.rs b/compile_to_rust_tests/src/main.rs index 61491e7..0a022a1 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, Vallish, + ValTrait, }; pub fn main() { @@ -65,21 +65,22 @@ pub fn main() { // 1.09s // Update: 1.06s +// Update: 0.99s pub fn fib(n: Val) -> Result { let mut _return = Val::Undefined; - let mut _tmp0 = op_less(Vallish::Ref(&n), Vallish::Own(2.0.to_val()))?; + let mut _tmp0 = op_less(&n, &2.0.to_val())?; if _tmp0.is_truthy() { _return = n; return Ok(_return); } - let mut _tmp1 = op_minus(Vallish::Ref(&n), Vallish::Own(1.0.to_val()))?; + let mut _tmp1 = op_minus(&n, &1.0.to_val())?; let mut _tmp2 = fib(_tmp1)?; - _tmp1 = op_minus(Vallish::Own(n), Vallish::Own(2.0.to_val()))?; + _tmp1 = op_minus(&n, &2.0.to_val())?; let mut _tmp3 = fib(_tmp1)?; - _return = op_plus(Vallish::Own(_tmp2), Vallish::Own(_tmp3))?; + _return = op_plus(&_tmp2, &_tmp3)?; return Ok(_return); } diff --git a/inputs/failing/copyCounting/arrayRef.ts b/inputs/failing/copyCounting/arrayRef.ts index 38d258a..30c0d79 100644 --- a/inputs/failing/copyCounting/arrayRef.ts +++ b/inputs/failing/copyCounting/arrayRef.ts @@ -1,4 +1,4 @@ -//! test_output(2) +//! test_output(3) // Should be: 1 export default function main() { diff --git a/inputs/failing/copyCounting/arraySwap.ts b/inputs/failing/copyCounting/arraySwap.ts index b691597..3d4fefc 100644 --- a/inputs/failing/copyCounting/arraySwap.ts +++ b/inputs/failing/copyCounting/arraySwap.ts @@ -1,4 +1,4 @@ -//! test_output(2) +//! test_output(3) // Should be: 1 export default function main() { diff --git a/inputs/passing/copyCounting/return.ts b/inputs/failing/copyCounting/return.ts similarity index 83% rename from inputs/passing/copyCounting/return.ts rename to inputs/failing/copyCounting/return.ts index cf1ca50..bce5232 100644 --- a/inputs/passing/copyCounting/return.ts +++ b/inputs/failing/copyCounting/return.ts @@ -1,4 +1,5 @@ -//! test_output(0) +//! test_output(1) +// Should be: 0 /// diff --git a/inputs/passing/copyCounting/subscript.ts b/inputs/failing/copyCounting/subscript.ts similarity index 79% rename from inputs/passing/copyCounting/subscript.ts rename to inputs/failing/copyCounting/subscript.ts index f356140..ca31b43 100644 --- a/inputs/passing/copyCounting/subscript.ts +++ b/inputs/failing/copyCounting/subscript.ts @@ -1,4 +1,5 @@ -//! test_output(0) +//! test_output(1) +// Should be: 0 /// diff --git a/inputs/passing/copyCounting/subscriptAssignment.ts b/inputs/failing/copyCounting/subscriptAssignment.ts similarity index 90% rename from inputs/passing/copyCounting/subscriptAssignment.ts rename to inputs/failing/copyCounting/subscriptAssignment.ts index 1f247ab..51d731d 100644 --- a/inputs/passing/copyCounting/subscriptAssignment.ts +++ b/inputs/failing/copyCounting/subscriptAssignment.ts @@ -1,4 +1,5 @@ -//! test_output(2) +//! test_output(3) +// Should be: 2 /// diff --git a/valuescript_vm/src/bytecode_decoder.rs b/valuescript_vm/src/bytecode_decoder.rs index 1353720..36c8b29 100644 --- a/valuescript_vm/src/bytecode_decoder.rs +++ b/valuescript_vm/src/bytecode_decoder.rs @@ -13,7 +13,6 @@ use crate::vs_object::VsObject; use crate::vs_symbol::VsSymbol; use crate::vs_value::ToVal; use crate::vs_value::Val; -use crate::Vallish; #[derive(Clone)] pub struct BytecodeDecoder { @@ -97,74 +96,66 @@ impl BytecodeDecoder { return BytecodeType::from_byte(self.peek_byte()); } - pub fn decode_vallish<'a>(&mut self, registers: &'a Vec) -> Vallish<'a> { - use Vallish::*; - + pub fn decode_val(&mut self, registers: &Vec) -> Val { return match self.decode_type() { BytecodeType::End => panic!("Cannot decode end"), - BytecodeType::Void => Own(Val::Void), - BytecodeType::Undefined => Own(Val::Undefined), - BytecodeType::Null => Own(Val::Null), - BytecodeType::False => Own(Val::Bool(false)), - BytecodeType::True => Own(Val::Bool(true)), - BytecodeType::SignedByte => Own((self.decode_signed_byte() as f64).to_val()), - BytecodeType::Number => Own(self.decode_number().to_val()), - BytecodeType::String => Own(self.decode_string().to_val()), - BytecodeType::Array => Own(self.decode_vec_val(registers).to_val()), + BytecodeType::Void => Val::Void, + BytecodeType::Undefined => Val::Undefined, + BytecodeType::Null => Val::Null, + BytecodeType::False => Val::Bool(false), + BytecodeType::True => Val::Bool(true), + BytecodeType::SignedByte => (self.decode_signed_byte() as f64).to_val(), + BytecodeType::Number => self.decode_number().to_val(), + BytecodeType::String => self.decode_string().to_val(), + BytecodeType::Array => self.decode_vec_val(registers).to_val(), BytecodeType::Object => { let mut string_map: BTreeMap = BTreeMap::new(); let mut symbol_map: BTreeMap = BTreeMap::new(); while self.peek_type() != BytecodeType::End { - let key = self.decode_vallish(registers); + let key = self.decode_val(registers); let value = self.decode_val(registers); - match key.get_ref() { + match key { Val::String(string) => string_map.insert(string.to_string(), value), - Val::Symbol(symbol) => symbol_map.insert(symbol.clone(), value), + Val::Symbol(symbol) => symbol_map.insert(symbol, value), key => string_map.insert(key.to_string(), value), }; } self.decode_type(); // End (TODO: assert) - Own( - VsObject { - string_map, - symbol_map, - prototype: None, - } - .to_val(), - ) - } - BytecodeType::Function => Own(self.decode_function(false)), - BytecodeType::Pointer => Own(self.decode_pointer(registers)), - BytecodeType::Register => match registers[self.decode_register_index().unwrap()] { - Val::Void => Own(Val::Undefined), - ref val => Ref(val), - }, - BytecodeType::TakeRegister => match registers[self.decode_register_index().unwrap()] { - Val::Void => Own(Val::Undefined), - ref val => Ref(val), - }, - BytecodeType::Builtin => Own(BUILTIN_VALS[self.decode_varsize_uint()]()), - BytecodeType::Class => Own( - VsClass { - constructor: self.decode_val(registers), - instance_prototype: self.decode_val(registers), + VsObject { + string_map, + symbol_map, + prototype: None, } - .to_val(), - ), - BytecodeType::BigInt => Own(self.decode_bigint().to_val()), - BytecodeType::GeneratorFunction => Own(self.decode_function(true)), + .to_val() + } + BytecodeType::Function => self.decode_function(false), + BytecodeType::Pointer => self.decode_pointer(registers), + BytecodeType::Register => match registers[self.decode_register_index().unwrap()].clone() { + Val::Void => Val::Undefined, + val => val, + }, + BytecodeType::TakeRegister => { + match registers[self.decode_register_index().unwrap()].clone() { + Val::Void => Val::Undefined, + val => val, + } + } + BytecodeType::Builtin => BUILTIN_VALS[self.decode_varsize_uint()](), + BytecodeType::Class => VsClass { + constructor: self.decode_val(registers), + instance_prototype: self.decode_val(registers), + } + .to_val(), + BytecodeType::BigInt => self.decode_bigint().to_val(), + BytecodeType::GeneratorFunction => self.decode_function(true), BytecodeType::Unrecognized => panic!("Unrecognized bytecode type at {}", self.pos - 1), }; } - pub fn decode_val(&mut self, registers: &Vec) -> Val { - return self.decode_vallish(registers).get_own(); - } - pub fn decode_vec_val(&mut self, registers: &Vec) -> Vec { let mut vals: Vec = Vec::new(); diff --git a/valuescript_vm/src/bytecode_stack_frame.rs b/valuescript_vm/src/bytecode_stack_frame.rs index 825790c..d0429b0 100644 --- a/valuescript_vm/src/bytecode_stack_frame.rs +++ b/valuescript_vm/src/bytecode_stack_frame.rs @@ -11,7 +11,6 @@ use crate::operations; use crate::stack_frame::FrameStepOk; use crate::stack_frame::FrameStepResult; use crate::stack_frame::{CallResult, StackFrame, StackFrameTrait}; -use crate::vallish::Vallish; use crate::vs_object::VsObject; use crate::vs_value::ToVal; use crate::vs_value::{LoadFunctionResult, Val, ValTrait}; @@ -36,26 +35,24 @@ pub struct CatchSetting { impl BytecodeStackFrame { pub fn apply_unary_op(&mut self, op: fn(input: &Val) -> Val) { - let input = self.decoder.decode_vallish(&self.registers); + let input = self.decoder.decode_val(&self.registers); let register_index = self.decoder.decode_register_index(); if register_index.is_some() { - self.registers[register_index.unwrap()] = op(input.get_ref()); + self.registers[register_index.unwrap()] = op(&input); } } pub fn apply_binary_op( &mut self, - op: fn(left: Vallish, right: Vallish) -> Result, + op: fn(left: &Val, right: &Val) -> Result, ) -> Result<(), Val> { - let left = self.decoder.decode_vallish(&self.registers); - let right = self.decoder.decode_vallish(&self.registers); + let left = self.decoder.decode_val(&self.registers); + let right = self.decoder.decode_val(&self.registers); - let register_index = self.decoder.decode_register_index(); - - if register_index.is_some() { - self.registers[register_index.unwrap()] = op(left, right)?; + if let Some(register_index) = self.decoder.decode_register_index() { + self.registers[register_index] = op(&left, &right)?; } Ok(()) @@ -158,7 +155,7 @@ impl StackFrameTrait for BytecodeStackFrame { match val { Val::Number(n) => *n += 1.0, Val::BigInt(bi) => *bi += 1, - _ => *val = operations::op_plus(Vallish::Ref(val), Vallish::Own(1.0.to_val()))?, + _ => *val = operations::op_plus(val, &1.0.to_val())?, }; } @@ -169,7 +166,7 @@ impl StackFrameTrait for BytecodeStackFrame { match val { Val::Number(n) => *n -= 1.0, Val::BigInt(bi) => *bi -= 1, - _ => *val = operations::op_minus(Vallish::Ref(val), Vallish::Own(1.0.to_val()))?, + _ => *val = operations::op_minus(val, &1.0.to_val())?, }; } @@ -193,7 +190,14 @@ impl StackFrameTrait for BytecodeStackFrame { OpGreater => self.apply_binary_op(operations::op_greater)?, OpGreaterEq => self.apply_binary_op(operations::op_greater_eq)?, OpNullishCoalesce => self.apply_binary_op(operations::op_nullish_coalesce)?, - OpOptionalChain => self.apply_binary_op(operations::op_optional_chain)?, + OpOptionalChain => { + let mut left = self.decoder.decode_val(&self.registers); + let right = self.decoder.decode_val(&self.registers); + + if let Some(register_index) = self.decoder.decode_register_index() { + self.registers[register_index] = operations::op_optional_chain(&mut left, &right)?; + } + } OpBitAnd => self.apply_binary_op(operations::op_bit_and)?, OpBitOr => self.apply_binary_op(operations::op_bit_or)?, @@ -299,7 +303,14 @@ impl StackFrameTrait for BytecodeStackFrame { } } - Sub => self.apply_binary_op(operations::op_sub)?, + Sub => { + let mut left = self.decoder.decode_val(&self.registers); + let right = self.decoder.decode_val(&self.registers); + + if let Some(register_index) = self.decoder.decode_register_index() { + self.registers[register_index] = operations::op_sub(&mut left, &right)?; + } + } SubMov => { // TODO: Ideally we would use a reference for the subscript (decode_vallish), but that would @@ -329,11 +340,11 @@ impl StackFrameTrait for BytecodeStackFrame { _ => ThisArg::Val(self.decoder.decode_val(&self.registers)), }; - let subscript = self.decoder.decode_vallish(&self.registers); + let subscript = self.decoder.decode_val(&self.registers); let fn_ = match &obj { - ThisArg::Register(reg_i) => self.registers[reg_i.clone()].sub(subscript.get_ref())?, - ThisArg::Val(val) => val.sub(subscript.get_ref())?, + ThisArg::Register(reg_i) => self.registers[*reg_i].sub(&subscript)?, + ThisArg::Val(val) => val.sub(&subscript)?, }; match fn_.load_function() { diff --git a/valuescript_vm/src/cat_stack_frame.rs b/valuescript_vm/src/cat_stack_frame.rs index 2c8ff99..a2a9f62 100644 --- a/valuescript_vm/src/cat_stack_frame.rs +++ b/valuescript_vm/src/cat_stack_frame.rs @@ -5,7 +5,6 @@ use crate::{ native_function::ThisWrapper, operations::op_sub, stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrame, StackFrameTrait}, - vallish::Vallish, vs_symbol::VsSymbol, vs_value::{ToVal, Val}, LoadFunctionResult, ValTrait, @@ -64,10 +63,7 @@ impl CatStackFrame { return Ok(FrameStepOk::Continue); } - let make_iter = op_sub( - Vallish::Ref(&arg), - Vallish::Own(VsSymbol::ITERATOR.to_val()), - )?; + let make_iter = op_sub(&mut arg, &VsSymbol::ITERATOR.to_val())?; match make_iter.load_function() { LoadFunctionResult::NotAFunction => Err("Non-iterable cat argument".to_type_error()), diff --git a/valuescript_vm/src/lib.rs b/valuescript_vm/src/lib.rs index 09e2071..ff7809d 100644 --- a/valuescript_vm/src/lib.rs +++ b/valuescript_vm/src/lib.rs @@ -18,7 +18,6 @@ pub mod operations; mod stack_frame; mod string_methods; mod todo_fn; -mod vallish; mod virtual_machine; pub mod vs_array; mod vs_class; @@ -28,6 +27,5 @@ mod vs_symbol; pub mod vs_value; pub use bytecode::Bytecode; -pub use vallish::Vallish; pub use virtual_machine::VirtualMachine; pub use vs_value::{LoadFunctionResult, ValTrait}; diff --git a/valuescript_vm/src/operations.rs b/valuescript_vm/src/operations.rs index e35a6dc..dbe1313 100644 --- a/valuescript_vm/src/operations.rs +++ b/valuescript_vm/src/operations.rs @@ -1,3 +1,4 @@ +use std::mem::take; use std::rc::Rc; use num_bigint::Sign; @@ -11,15 +12,14 @@ use crate::native_function::native_fn; use crate::native_function::NativeFunction; use crate::number_methods::op_sub_number; use crate::string_methods::op_sub_string; -use crate::vallish::Vallish; use crate::vs_value::ToVal; use crate::vs_value::Val; use crate::vs_value::ValTrait; use crate::vs_value::VsType; -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(); +pub fn op_plus(left: &Val, right: &Val) -> Result { + let left_prim = left.to_primitive(); + let right_prim = right.to_primitive(); let left_type = left_prim.typeof_(); let right_type = right_prim.typeof_(); @@ -51,16 +51,13 @@ pub fn op_unary_plus(input: &Val) -> Val { } } -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()) { +pub fn op_minus(left: &Val, right: &Val) -> Result { + match (left.as_bigint_data(), right.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_ref.to_number() - right_ref.to_number())), + _ => Ok(Val::Number(left.to_number() - right.to_number())), } } @@ -71,44 +68,32 @@ pub fn op_unary_minus(input: &Val) -> Val { } } -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()) { +pub fn op_mul(left: &Val, right: &Val) -> Result { + match (left.as_bigint_data(), right.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_ref.to_number() * right_ref.to_number())), + _ => Ok(Val::Number(left.to_number() * right.to_number())), } } -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()) { +pub fn op_div(left: &Val, right: &Val) -> Result { + match (left.as_bigint_data(), right.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_ref.to_number() / right_ref.to_number())), + _ => Ok(Val::Number(left.to_number() / right.to_number())), } } -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()) { +pub fn op_mod(left: &Val, right: &Val) -> Result { + match (left.as_bigint_data(), right.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_ref.to_number() % right_ref.to_number())), + _ => Ok(Val::Number(left.to_number() % right.to_number())), } } -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()) { +pub fn op_exp(left: &Val, right: &Val) -> Result { + match (left.as_bigint_data(), right.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()); @@ -122,15 +107,13 @@ pub fn op_exp(left: Vallish, right: Vallish) -> 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_ref.to_number().powf(right_ref.to_number()), - )), + _ => Ok(Val::Number(left.to_number().powf(right.to_number()))), } } -pub fn op_eq_impl(left: Vallish, right: Vallish) -> Result { - Ok(match (left.get_ref(), right.get_ref()) { - (left_ref, Val::Undefined | Val::Null) => match left_ref { +pub fn op_eq_impl(left: &Val, right: &Val) -> Result { + Ok(match (left, right) { + (left, Val::Undefined | Val::Null) => match left { Val::Undefined | Val::Null => true, _ => false, }, @@ -142,19 +125,16 @@ pub fn op_eq_impl(left: Vallish, right: Vallish) -> Result { }) } -pub fn op_eq(left: Vallish, right: Vallish) -> Result { +pub fn op_eq(left: &Val, right: &Val) -> Result { Ok(Val::Bool(op_eq_impl(left, right)?)) } -pub fn op_ne(left: Vallish, right: Vallish) -> Result { +pub fn op_ne(left: &Val, right: &Val) -> Result { Ok(Val::Bool(!op_eq_impl(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) { +pub fn op_triple_eq_impl(left: &Val, right: &Val) -> Result { + Ok(match (left, right) { (Val::Undefined, Val::Undefined) => true, (Val::Null, Val::Null) => true, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool == right_bool, @@ -162,7 +142,7 @@ pub fn op_triple_eq_impl(left: Vallish, right: Vallish) -> 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_ref.typeof_() != right_ref.typeof_() { + if left.typeof_() != right.typeof_() { false } else { return Err("TODO".to_error()); @@ -171,37 +151,34 @@ pub fn op_triple_eq_impl(left: Vallish, right: Vallish) -> Result { }) } -pub fn op_triple_eq(left: Vallish, right: Vallish) -> Result { +pub fn op_triple_eq(left: &Val, right: &Val) -> Result { let is_eq = op_triple_eq_impl(left, right)?; Ok(Val::Bool(is_eq)) } -pub fn op_triple_ne(left: Vallish, right: Vallish) -> Result { +pub fn op_triple_ne(left: &Val, right: &Val) -> Result { let is_eq = op_triple_eq_impl(left, right)?; Ok(Val::Bool(!is_eq)) } -pub fn op_and(left: Vallish, right: Vallish) -> Result { - let truthy = left.get_ref().is_truthy(); +pub fn op_and(left: &Val, right: &Val) -> Result { + let truthy = left.is_truthy(); - Ok((if truthy { right } else { left }).get_own()) + Ok((if truthy { right } else { left }).clone()) } -pub fn op_or(left: Vallish, right: Vallish) -> Result { - let truthy = left.get_ref().is_truthy(); +pub fn op_or(left: &Val, right: &Val) -> Result { + let truthy = left.is_truthy(); - Ok((if truthy { left } else { right }).get_own()) + Ok((if truthy { left } else { right }).clone()) } pub fn op_not(input: &Val) -> Val { return Val::Bool(!input.is_truthy()); } -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) { +pub fn op_less(left: &Val, right: &Val) -> Result { + Ok(Val::Bool(match (left, right) { (Val::Undefined, Val::Undefined) => false, (Val::Null, Val::Null) => false, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool < right_bool, @@ -209,7 +186,7 @@ pub fn op_less(left: Vallish, right: Vallish) -> 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_ref.typeof_() == VsType::Undefined || right_ref.typeof_() == VsType::Undefined { + if left.typeof_() == VsType::Undefined || right.typeof_() == VsType::Undefined { false } else { return Err("TODO".to_error()); @@ -218,8 +195,8 @@ pub fn op_less(left: Vallish, right: Vallish) -> Result { })) } -pub fn op_less_eq(left: Vallish, right: Vallish) -> Result { - Ok(Val::Bool(match (left.get_ref(), right.get_ref()) { +pub fn op_less_eq(left: &Val, right: &Val) -> Result { + Ok(Val::Bool(match (left, right) { (Val::Undefined, Val::Undefined) => false, (Val::Null, Val::Null) => true, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool <= right_bool, @@ -230,8 +207,8 @@ pub fn op_less_eq(left: Vallish, right: Vallish) -> Result { })) } -pub fn op_greater(left: Vallish, right: Vallish) -> Result { - Ok(Val::Bool(match (left.get_ref(), right.get_ref()) { +pub fn op_greater(left: &Val, right: &Val) -> Result { + Ok(Val::Bool(match (left, right) { (Val::Undefined, Val::Undefined) => false, (Val::Null, Val::Null) => false, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool > right_bool, @@ -242,8 +219,8 @@ pub fn op_greater(left: Vallish, right: Vallish) -> Result { })) } -pub fn op_greater_eq(left: Vallish, right: Vallish) -> Result { - Ok(Val::Bool(match (left.get_ref(), right.get_ref()) { +pub fn op_greater_eq(left: &Val, right: &Val) -> Result { + Ok(Val::Bool(match (left, right) { (Val::Undefined, Val::Undefined) => false, (Val::Null, Val::Null) => true, (Val::Bool(left_bool), Val::Bool(right_bool)) => left_bool >= right_bool, @@ -254,14 +231,14 @@ pub fn op_greater_eq(left: Vallish, right: Vallish) -> Result { })) } -pub fn op_nullish_coalesce(left: Vallish, right: Vallish) -> Result { - let nullish = left.get_ref().is_nullish(); +pub fn op_nullish_coalesce(left: &Val, right: &Val) -> Result { + let nullish = left.is_nullish(); - Ok((if nullish { right } else { left }).get_own()) + Ok((if nullish { right } else { left }).clone()) } -pub fn op_optional_chain(left: Vallish, right: Vallish) -> Result { - return match left.get_ref() { +pub fn op_optional_chain(left: &mut Val, right: &Val) -> Result { + return match left { Val::Undefined | Val::Null => Ok(Val::Undefined), _ => op_sub(left, right), @@ -288,29 +265,23 @@ pub fn to_u32(x: f64) -> u32 { return int1 as u32; } -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()) { +pub fn op_bit_and(left: &Val, right: &Val) -> Result { + match (left.as_bigint_data(), right.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_ref.to_number()) & to_i32(right_ref.to_number()); + let res_i32 = to_i32(left.to_number()) & to_i32(right.to_number()); Ok(Val::Number(res_i32 as f64)) } } } -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()) { +pub fn op_bit_or(left: &Val, right: &Val) -> Result { + match (left.as_bigint_data(), right.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_ref.to_number()) | to_i32(right_ref.to_number()); + let res_i32 = to_i32(left.to_number()) | to_i32(right.to_number()); Ok(Val::Number(res_i32 as f64)) } } @@ -326,62 +297,50 @@ pub fn op_bit_not(input: &Val) -> Val { } } -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()) { +pub fn op_bit_xor(left: &Val, right: &Val) -> Result { + match (left.as_bigint_data(), right.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_ref.to_number()) ^ to_i32(right_ref.to_number()); + let res_i32 = to_i32(left.to_number()) ^ to_i32(right.to_number()); Ok(Val::Number(res_i32 as f64)) } } } -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()) { +pub fn op_left_shift(left: &Val, right: &Val) -> Result { + match (left.as_bigint_data(), right.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_ref.to_number()) << (to_u32(right_ref.to_number()) & 0x1f); + let res_i32 = to_i32(left.to_number()) << (to_u32(right.to_number()) & 0x1f); Ok(Val::Number(res_i32 as f64)) } } } -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()) { +pub fn op_right_shift(left: &Val, right: &Val) -> Result { + match (left.as_bigint_data(), right.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_ref.to_number()) >> (to_u32(right_ref.to_number()) & 0x1f); + let res_i32 = to_i32(left.to_number()) >> (to_u32(right.to_number()) & 0x1f); Ok(Val::Number(res_i32 as f64)) } } } -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()) { +pub fn op_right_shift_unsigned(left: &Val, right: &Val) -> Result { + match (left.as_bigint_data(), right.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_ref.to_number()) >> (to_u32(right_ref.to_number()) & 0x1f); + let res_u32 = to_u32(left.to_number()) >> (to_u32(right.to_number()) & 0x1f); Ok(Val::Number(res_u32 as f64)) } } @@ -406,41 +365,38 @@ pub fn op_typeof(input: &Val) -> Val { .to_val() } -pub fn op_instance_of(_left: Vallish, _right: Vallish) -> Result { +pub fn op_instance_of(_left: &Val, _right: &Val) -> Result { Err("TODO: op_instance_of".to_error()) } -pub fn op_in(_left: Vallish, _right: Vallish) -> Result { +pub fn op_in(_left: &Val, _right: &Val) -> Result { Err("TODO: op_in".to_error()) } -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 { +pub fn op_sub(left: &mut Val, right: &Val) -> Result { + match left { 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_ref.to_string().as_str() { + Val::Bool(_) => Ok(match right.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_ref)), - Val::BigInt(bigint) => Ok(op_sub_bigint(bigint, right_ref)), + Val::Number(number) => Ok(op_sub_number(*number, right)), + Val::BigInt(bigint) => Ok(op_sub_bigint(bigint, right)), Val::Symbol(_) => Ok(Val::Undefined), - Val::String(string_data) => Ok(op_sub_string(string_data, right_ref)), + Val::String(string_data) => Ok(op_sub_string(string_data, right)), Val::Array(array_data) => { - let right_index = match right_ref.to_index() { + let right_index = match right.to_index() { None => { // FIXME: Inefficient to_string() that gets duplicated // when subscripting the object - if right_ref.to_string() == "length" { + if right.to_string() == "length" { return Ok(Val::Number(array_data.elements.len() as f64)); } - return Ok(array_data.object.sub(right_ref)); + return Ok(array_data.object.sub(right)); } Some(i) => i, }; @@ -449,18 +405,21 @@ pub fn op_sub(left: Vallish, right: Vallish) -> Result { return Ok(Val::Undefined); } - let res = array_data.elements[right_index].clone(); + let res = match Rc::get_mut(array_data) { + Some(array_data) => take(&mut array_data.elements[right_index]), + None => array_data.elements[right_index].clone(), + }; return Ok(match res { Val::Void => Val::Undefined, _ => res, }); } - Val::Object(object_data) => Ok(object_data.sub(right_ref)), + Val::Object(object_data) => Ok(object_data.sub(right)), // TODO: move on single ref Val::Function(_) | Val::Class(_) => Ok(Val::Undefined), - 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() { + 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.clone(), "count" => (*cc.count.borrow() as f64).to_val(), _ => Val::Undefined, diff --git a/valuescript_vm/src/vallish.rs b/valuescript_vm/src/vallish.rs deleted file mode 100644 index e817038..0000000 --- a/valuescript_vm/src/vallish.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::vs_value::Val; - -pub enum Vallish<'a> { - Own(Val), - Ref(&'a Val), -} - -impl<'a> Vallish<'a> { - pub fn get_own(self) -> Val { - match self { - Vallish::Own(val) => val, - Vallish::Ref(val) => val.clone(), - } - } - - pub fn get_ref(&self) -> &Val { - match self { - Vallish::Own(val) => val, - Vallish::Ref(val) => val, - } - } -} diff --git a/valuescript_vm/src/vs_array.rs b/valuescript_vm/src/vs_array.rs index 0c63137..0f98c4f 100644 --- a/valuescript_vm/src/vs_array.rs +++ b/valuescript_vm/src/vs_array.rs @@ -17,7 +17,6 @@ use crate::iteration::array_iterator::ArrayIterator; use crate::native_function::{native_fn, NativeFunction}; use crate::operations::op_triple_eq_impl; use crate::todo_fn::TODO; -use crate::vallish::Vallish; use crate::vs_class::VsClass; use crate::vs_object::VsObject; use crate::vs_symbol::VsSymbol; @@ -343,7 +342,7 @@ static INCLUDES: NativeFunction = native_fn(|this, params| { let search_param = params.get(0).unwrap_or(&Val::Undefined); for elem in &array_data.elements { - let is_eq = op_triple_eq_impl(Vallish::Ref(elem), Vallish::Ref(search_param)) + let is_eq = op_triple_eq_impl(elem, search_param) .map_err(|e| e.to_string()) .unwrap(); // TODO: Exception @@ -364,12 +363,9 @@ static INDEX_OF: NativeFunction = native_fn(|this, params| { 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( - Vallish::Ref(&array_data.elements[i]), - Vallish::Ref(search_param), - ) - .map_err(|e| e.to_string()) - .unwrap(); // TODO: Exception + let is_eq = op_triple_eq_impl(&array_data.elements[i], search_param) + .map_err(|e| e.to_string()) + .unwrap(); // TODO: Exception if is_eq { return Ok(Val::Number(i as f64)); @@ -424,12 +420,9 @@ static LAST_INDEX_OF: NativeFunction = native_fn(|this, params| { 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( - Vallish::Ref(&array_data.elements[i]), - Vallish::Ref(search_param), - ) - .map_err(|e| e.to_string()) - .unwrap(); // TODO: Exception + let is_eq = op_triple_eq_impl(&array_data.elements[i], 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_value.rs b/valuescript_vm/src/vs_value.rs index 3a79a6a..55f4e43 100644 --- a/valuescript_vm/src/vs_value.rs +++ b/valuescript_vm/src/vs_value.rs @@ -11,7 +11,6 @@ use crate::copy_counter::CopyCounter; use crate::native_function::ThisWrapper; use crate::operations::{op_sub, op_submov}; use crate::stack_frame::StackFrame; -use crate::vallish::Vallish; use crate::vs_array::VsArray; use crate::vs_class::VsClass; use crate::vs_function::VsFunction; @@ -352,8 +351,8 @@ impl ValTrait for Val { } fn sub(&self, key: &Val) -> Result { - // TODO: Avoid indirection? - op_sub(Vallish::Ref(self), Vallish::Ref(key)) + // TODO: mut version? + op_sub(&mut self.clone(), key) } fn submov(&mut self, key: &Val, value: Val) -> Result<(), Val> {