diff --git a/valuescript_vm/src/builtins/array_builtin.rs b/valuescript_vm/src/builtins/array_builtin.rs index da8ed5c..3543162 100644 --- a/valuescript_vm/src/builtins/array_builtin.rs +++ b/valuescript_vm/src/builtins/array_builtin.rs @@ -122,6 +122,8 @@ static FROM: NativeFunction = NativeFunction { first_param.clone(), Val::String(Rc::new("length".to_string())), ) + .map_err(|e| e.val_to_string()) + .unwrap() // TODO: Exception .to_number(); if len.is_sign_negative() || len.is_nan() { @@ -139,7 +141,11 @@ static FROM: NativeFunction = NativeFunction { // TODO: We should probably use a frame and step through this // Also using op_sub is slow. Should write specialized stuff instead. for i in 0..len { - arr.push(op_sub(first_param.clone(), Val::Number(i as f64))); + arr.push( + op_sub(first_param.clone(), Val::Number(i as f64)) + .map_err(|e| e.val_to_string()) + .unwrap(), // TODO: Exception + ); } Val::Array(Rc::new(VsArray::from(arr))) diff --git a/valuescript_vm/src/bytecode_stack_frame.rs b/valuescript_vm/src/bytecode_stack_frame.rs index 0ef667b..42b204a 100644 --- a/valuescript_vm/src/bytecode_stack_frame.rs +++ b/valuescript_vm/src/bytecode_stack_frame.rs @@ -30,15 +30,20 @@ impl BytecodeStackFrame { } } - pub fn apply_binary_op(&mut self, op: fn(left: Val, right: Val) -> Val) { + pub fn apply_binary_op( + &mut self, + op: fn(left: Val, right: Val) -> Result, + ) -> Result<(), Val> { 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); + self.registers[register_index.unwrap()] = op(left, right)?; } + + Ok(()) } pub fn transfer_parameters(&mut self, new_frame: &mut StackFrame) { @@ -110,52 +115,52 @@ impl StackFrameTrait for BytecodeStackFrame { OpInc => { let register_index = self.decoder.decode_register_index().unwrap(); let mut val = self.registers[register_index].clone(); - val = operations::op_plus(val, Val::Number(1_f64)); + val = operations::op_plus(val, Val::Number(1_f64))?; // TODO: BigInt self.registers[register_index] = val; } OpDec => { let register_index = self.decoder.decode_register_index().unwrap(); let mut val = self.registers[register_index].clone(); - val = operations::op_minus(val, Val::Number(1_f64)); + val = operations::op_minus(val, Val::Number(1_f64))?; // TODO: BigInt self.registers[register_index] = val; } - OpPlus => self.apply_binary_op(operations::op_plus), - OpMinus => self.apply_binary_op(operations::op_minus), - OpMul => self.apply_binary_op(operations::op_mul), - OpDiv => self.apply_binary_op(operations::op_div), - OpMod => self.apply_binary_op(operations::op_mod), - OpExp => self.apply_binary_op(operations::op_exp), - OpEq => self.apply_binary_op(operations::op_eq), - OpNe => self.apply_binary_op(operations::op_ne), - OpTripleEq => self.apply_binary_op(operations::op_triple_eq), - OpTripleNe => self.apply_binary_op(operations::op_triple_ne), - OpAnd => self.apply_binary_op(operations::op_and), - OpOr => self.apply_binary_op(operations::op_or), + OpPlus => self.apply_binary_op(operations::op_plus)?, + OpMinus => self.apply_binary_op(operations::op_minus)?, + OpMul => self.apply_binary_op(operations::op_mul)?, + OpDiv => self.apply_binary_op(operations::op_div)?, + OpMod => self.apply_binary_op(operations::op_mod)?, + OpExp => self.apply_binary_op(operations::op_exp)?, + OpEq => self.apply_binary_op(operations::op_eq)?, + OpNe => self.apply_binary_op(operations::op_ne)?, + OpTripleEq => self.apply_binary_op(operations::op_triple_eq)?, + OpTripleNe => self.apply_binary_op(operations::op_triple_ne)?, + OpAnd => self.apply_binary_op(operations::op_and)?, + OpOr => self.apply_binary_op(operations::op_or)?, OpNot => self.apply_unary_op(operations::op_not), - OpLess => self.apply_binary_op(operations::op_less), - OpLessEq => self.apply_binary_op(operations::op_less_eq), - 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), - OpBitAnd => self.apply_binary_op(operations::op_bit_and), - OpBitOr => self.apply_binary_op(operations::op_bit_or), + OpLess => self.apply_binary_op(operations::op_less)?, + OpLessEq => self.apply_binary_op(operations::op_less_eq)?, + 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)?, + OpBitAnd => self.apply_binary_op(operations::op_bit_and)?, + OpBitOr => self.apply_binary_op(operations::op_bit_or)?, OpBitNot => self.apply_unary_op(operations::op_bit_not), - OpBitXor => self.apply_binary_op(operations::op_bit_xor), - OpLeftShift => self.apply_binary_op(operations::op_left_shift), - OpRightShift => self.apply_binary_op(operations::op_right_shift), - OpRightShiftUnsigned => self.apply_binary_op(operations::op_right_shift_unsigned), + OpBitXor => self.apply_binary_op(operations::op_bit_xor)?, + OpLeftShift => self.apply_binary_op(operations::op_left_shift)?, + OpRightShift => self.apply_binary_op(operations::op_right_shift)?, + OpRightShiftUnsigned => self.apply_binary_op(operations::op_right_shift_unsigned)?, TypeOf => self.apply_unary_op(operations::op_typeof), - InstanceOf => self.apply_binary_op(operations::op_instance_of), - In => self.apply_binary_op(operations::op_in), + InstanceOf => self.apply_binary_op(operations::op_instance_of)?, + In => self.apply_binary_op(operations::op_in)?, Call => { let fn_ = self.decoder.decode_val(&self.registers); @@ -244,7 +249,7 @@ impl StackFrameTrait for BytecodeStackFrame { } } - Sub => self.apply_binary_op(operations::op_sub), + Sub => self.apply_binary_op(operations::op_sub)?, SubMov => { let subscript = self.decoder.decode_val(&self.registers); @@ -253,7 +258,7 @@ impl StackFrameTrait for BytecodeStackFrame { let register_index = self.decoder.decode_register_index().unwrap(); let mut target = self.registers[register_index].clone(); // TODO: Lift - operations::op_submov(&mut target, subscript, value); + operations::op_submov(&mut target, subscript, value)?; self.registers[register_index] = target; } @@ -275,7 +280,7 @@ impl StackFrameTrait for BytecodeStackFrame { ThisArg::Val(val) => val.clone(), }, subscript, - ); + )?; match fn_.load_function() { LoadFunctionResult::NotAFunction => { diff --git a/valuescript_vm/src/operations.rs b/valuescript_vm/src/operations.rs index 9764729..e39449d 100644 --- a/valuescript_vm/src/operations.rs +++ b/valuescript_vm/src/operations.rs @@ -12,7 +12,23 @@ use super::vs_value::Val; use super::vs_value::ValTrait; use super::vs_value::VsType; -pub fn op_plus(left: Val, right: Val) -> Val { +macro_rules! format_err { + ($fmt:expr $(, $($arg:expr),*)?) => {{ + let formatted_string = format!($fmt $(, $($arg),*)?); + + // TODO: This should be a proper error type + Err(Val::String(Rc::new(formatted_string))) + }}; +} + +macro_rules! format_string { + ($fmt:expr $(, $($arg:expr),*)?) => {{ + let formatted_string = format!($fmt $(, $($arg),*)?); + Val::String(Rc::new(formatted_string)) + }}; +} + +pub fn op_plus(left: Val, right: Val) -> Result { let left_prim = left.to_primitive(); let right_prim = right.to_primitive(); @@ -20,25 +36,27 @@ pub fn op_plus(left: Val, right: Val) -> Val { let right_type = right_prim.typeof_(); if left_type == VsType::String || right_type == VsType::String { - return Val::String(Rc::new( + return Ok(Val::String(Rc::new( left_prim.val_to_string() + &right_prim.val_to_string(), - )); + ))); } if left_type == VsType::BigInt || right_type == VsType::BigInt { if left_type != right_type { - std::panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)"); + return Err(Val::String(Rc::new( + "TypeError: Cannot mix BigInt and other types".to_string(), + ))); } match (left_prim.as_bigint_data(), right_prim.as_bigint_data()) { (Some(left_bigint), Some(right_bigint)) => { - return Val::BigInt(left_bigint + right_bigint); + return Ok(Val::BigInt(left_bigint + right_bigint)); } - _ => std::panic!("Not implemented"), + _ => return format_err!("TODO"), } } - return Val::Number(left_prim.to_number() + right_prim.to_number()); + return Ok(Val::Number(left_prim.to_number() + right_prim.to_number())); } pub fn op_unary_plus(input: Val) -> Val { @@ -48,13 +66,13 @@ pub fn op_unary_plus(input: Val) -> Val { } } -pub fn op_minus(left: Val, right: Val) -> Val { +pub fn op_minus(left: Val, right: Val) -> Result { match (left.as_bigint_data(), right.as_bigint_data()) { - (Some(left_bigint), Some(right_bigint)) => Val::BigInt(left_bigint - right_bigint), - (Some(_), None) | (None, Some(_)) => { - std::panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)") - } - _ => Val::Number(left.to_number() - right.to_number()), + (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint - right_bigint)), + (Some(_), None) | (None, Some(_)) => Err(Val::String(Rc::new( + "TypeError: Cannot mix BigInt with other types".to_string(), + ))), + _ => Ok(Val::Number(left.to_number() - right.to_number())), } } @@ -65,85 +83,83 @@ pub fn op_unary_minus(input: Val) -> Val { } } -pub fn op_mul(left: Val, right: Val) -> Val { +pub fn op_mul(left: Val, right: Val) -> Result { match (left.as_bigint_data(), right.as_bigint_data()) { - (Some(left_bigint), Some(right_bigint)) => Val::BigInt(left_bigint * right_bigint), + (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint * right_bigint)), (Some(_), None) | (None, Some(_)) => { - std::panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)") + format_err!("TypeError: Cannot mix BigInt with other types") } - _ => Val::Number(left.to_number() * right.to_number()), + _ => Ok(Val::Number(left.to_number() * right.to_number())), } } -pub fn op_div(left: Val, right: Val) -> Val { +pub fn op_div(left: Val, right: Val) -> Result { match (left.as_bigint_data(), right.as_bigint_data()) { - (Some(left_bigint), Some(right_bigint)) => Val::BigInt(left_bigint / right_bigint), + (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint / right_bigint)), (Some(_), None) | (None, Some(_)) => { - std::panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)") + format_err!("TypeError: Cannot mix BigInt with other types") } - _ => Val::Number(left.to_number() / right.to_number()), + _ => Ok(Val::Number(left.to_number() / right.to_number())), } } -pub fn op_mod(left: Val, right: Val) -> Val { +pub fn op_mod(left: Val, right: Val) -> Result { match (left.as_bigint_data(), right.as_bigint_data()) { - (Some(left_bigint), Some(right_bigint)) => Val::BigInt(left_bigint % right_bigint), + (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint % right_bigint)), (Some(_), None) | (None, Some(_)) => { - std::panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)") + format_err!("TypeError: Cannot mix BigInt with other types") } - _ => Val::Number(left.to_number() % right.to_number()), + _ => Ok(Val::Number(left.to_number() % right.to_number())), } } -pub fn op_exp(left: Val, right: Val) -> Val { +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 { - std::panic!("TODO: Exceptions (RangeError: Exponent must be non-negative)"); + return format_err!("RangeError: Exponent must be non-negative"); } let exp = match right_bigint.to_u32() { Some(exp) => exp, - None => { - std::panic!("TODO: Exceptions (RangeError: Exponent must be less than 2^32)") - } + None => return format_err!("RangeError: Exponent must be less than 2^32"), }; - Val::BigInt(left_bigint.pow(exp)) + Ok(Val::BigInt(left_bigint.pow(exp))) } (Some(_), None) | (None, Some(_)) => { - std::panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)") + format_err!("TypeError: Cannot mix BigInt with other types") } - _ => Val::Number(left.to_number().powf(right.to_number())), + _ => Ok(Val::Number(left.to_number().powf(right.to_number()))), } } -pub fn op_eq(left: Val, right: Val) -> Val { - Val::Bool(match (left, right) { +pub fn op_eq(left: Val, right: Val) -> Result { + Ok(Val::Bool(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, (Val::Number(left_number), Val::Number(right_number)) => left_number == right_number, (Val::String(left_string), Val::String(right_string)) => left_string == right_string, (Val::BigInt(left_bigint), Val::BigInt(right_bigint)) => left_bigint == right_bigint, - _ => panic!("TODO"), - }) + _ => return format_err!("TODO"), + })) } -pub fn op_ne(left: Val, right: Val) -> Val { - Val::Bool(match (left, right) { +pub fn op_ne(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, (Val::Number(left_number), Val::Number(right_number)) => left_number != right_number, (Val::String(left_string), Val::String(right_string)) => left_string != right_string, (Val::BigInt(left_bigint), Val::BigInt(right_bigint)) => left_bigint != right_bigint, - _ => panic!("TODO"), - }) + _ => return format_err!("TODO"), + })) } -pub fn op_triple_eq_impl(left: Val, right: Val) -> bool { - match (&left, &right) { +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, @@ -154,34 +170,36 @@ pub fn op_triple_eq_impl(left: Val, right: Val) -> bool { if left.typeof_() != right.typeof_() { false } else { - panic!("TODO") + return format_err!("TODO"); } } - } + }) } -pub fn op_triple_eq(left: Val, right: Val) -> Val { - Val::Bool(op_triple_eq_impl(left, right)) +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: Val, right: Val) -> Val { - Val::Bool(!op_triple_eq_impl(left, right)) +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: Val, right: Val) -> Val { - return if left.is_truthy() { right } else { left }; +pub fn op_and(left: Val, right: Val) -> Result { + Ok(if left.is_truthy() { right } else { left }) } -pub fn op_or(left: Val, right: Val) -> Val { - return if left.is_truthy() { left } else { right }; +pub fn op_or(left: Val, right: Val) -> Result { + Ok(if left.is_truthy() { left } else { right }) } pub fn op_not(input: Val) -> Val { return Val::Bool(!input.is_truthy()); } -pub fn op_less(left: Val, right: Val) -> Val { - Val::Bool(match (&left, &right) { +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, @@ -192,56 +210,55 @@ pub fn op_less(left: Val, right: Val) -> Val { if left.typeof_() == VsType::Undefined || right.typeof_() == VsType::Undefined { false } else { - panic!("TODO") + return format_err!("TODO"); } } - }) + })) } -pub fn op_less_eq(left: Val, right: Val) -> Val { - Val::Bool(match (left, right) { +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, (Val::Number(left_number), Val::Number(right_number)) => left_number <= right_number, (Val::String(left_string), Val::String(right_string)) => left_string <= right_string, (Val::BigInt(left_bigint), Val::BigInt(right_bigint)) => left_bigint <= right_bigint, - _ => panic!("TODO"), - }) + _ => return format_err!("TODO"), + })) } -pub fn op_greater(left: Val, right: Val) -> Val { - Val::Bool(match (left, right) { +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, (Val::Number(left_number), Val::Number(right_number)) => left_number > right_number, (Val::String(left_string), Val::String(right_string)) => left_string > right_string, (Val::BigInt(left_bigint), Val::BigInt(right_bigint)) => left_bigint > right_bigint, - _ => panic!("TODO"), - }) + _ => return format_err!("TODO"), + })) } -pub fn op_greater_eq(left: Val, right: Val) -> Val { - Val::Bool(match (left, right) { +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, (Val::Number(left_number), Val::Number(right_number)) => left_number >= right_number, (Val::String(left_string), Val::String(right_string)) => left_string >= right_string, (Val::BigInt(left_bigint), Val::BigInt(right_bigint)) => left_bigint >= right_bigint, - _ => panic!("TODO"), - }) + _ => return format_err!("TODO"), + })) } -pub fn op_nullish_coalesce(left: Val, right: Val) -> Val { - return if left.is_nullish() { right } else { left }; +pub fn op_nullish_coalesce(left: Val, right: Val) -> Result { + Ok(if left.is_nullish() { right } else { left }) } -pub fn op_optional_chain(left: Val, right: Val) -> Val { +pub fn op_optional_chain(left: Val, right: Val) -> Result { return match left { - Val::Undefined => Val::Undefined, - Val::Null => Val::Undefined, + Val::Undefined | Val::Null => Ok(Val::Undefined), _ => op_sub(left, right), }; @@ -267,28 +284,28 @@ pub fn to_u32(x: f64) -> u32 { return int1 as u32; } -pub fn op_bit_and(left: Val, right: Val) -> Val { +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)) => Val::BigInt(left_bigint & right_bigint), + (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint & right_bigint)), (Some(_), None) | (None, Some(_)) => { - panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)") + format_err!("TypeError: Cannot mix BigInt with other types") } _ => { let res_i32 = to_i32(left.to_number()) & to_i32(right.to_number()); - Val::Number(res_i32 as f64) + Ok(Val::Number(res_i32 as f64)) } } } -pub fn op_bit_or(left: Val, right: Val) -> Val { +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)) => Val::BigInt(left_bigint | right_bigint), + (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint | right_bigint)), (Some(_), None) | (None, Some(_)) => { - panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)") + format_err!("TypeError: Cannot mix BigInt with other types") } _ => { let res_i32 = to_i32(left.to_number()) | to_i32(right.to_number()); - Val::Number(res_i32 as f64) + Ok(Val::Number(res_i32 as f64)) } } } @@ -303,60 +320,61 @@ pub fn op_bit_not(input: Val) -> Val { } } -pub fn op_bit_xor(left: Val, right: Val) -> Val { +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)) => Val::BigInt(left_bigint ^ right_bigint), + (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(left_bigint ^ right_bigint)), (Some(_), None) | (None, Some(_)) => { - panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)") + format_err!("TypeError: Cannot mix BigInt with other types") } _ => { let res_i32 = to_i32(left.to_number()) ^ to_i32(right.to_number()); - Val::Number(res_i32 as f64) + Ok(Val::Number(res_i32 as f64)) } } } -pub fn op_left_shift(left: Val, right: Val) -> Val { +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)) => { - Val::BigInt(left_bigint << right_bigint.to_i64().expect("TODO")) - } + (Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt( + left_bigint << right_bigint.to_i64().expect("TODO"), + )), (Some(_), None) | (None, Some(_)) => { - panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)") + format_err!("TypeError: Cannot mix BigInt with other types") } _ => { let res_i32 = to_i32(left.to_number()) << (to_u32(right.to_number()) & 0x1f); - Val::Number(res_i32 as f64) + Ok(Val::Number(res_i32 as f64)) } } } -pub fn op_right_shift(left: Val, right: Val) -> Val { +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)) => { - Val::BigInt(left_bigint >> right_bigint.to_i64().expect("TODO")) + let right_i64 = right_bigint.to_i64().ok_or(format_string!("TODO"))?; + Ok(Val::BigInt(left_bigint >> right_i64)) } (Some(_), None) | (None, Some(_)) => { - panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)") + format_err!("TypeError: Cannot mix BigInt with other types") } _ => { let res_i32 = to_i32(left.to_number()) >> (to_u32(right.to_number()) & 0x1f); - Val::Number(res_i32 as f64) + Ok(Val::Number(res_i32 as f64)) } } } -pub fn op_right_shift_unsigned(left: Val, right: Val) -> Val { +pub fn op_right_shift_unsigned(left: Val, right: Val) -> Result { match (left.as_bigint_data(), right.as_bigint_data()) { (Some(_), Some(_)) => { - panic!("TODO: Exceptions (TypeError: BigInts don't support unsigned right shift)") + format_err!("TypeError: BigInts don't support unsigned right shift") } (Some(_), None) | (None, Some(_)) => { - panic!("TODO: Exceptions (TypeError: Cannot mix BigInt with other types)") + format_err!("TypeError: Cannot mix BigInt with other types") } _ => { let res_u32 = to_u32(left.to_number()) >> (to_u32(right.to_number()) & 0x1f); - Val::Number(res_u32 as f64) + Ok(Val::Number(res_u32 as f64)) } } } @@ -378,74 +396,71 @@ pub fn op_typeof(input: Val) -> Val { })); } -pub fn op_instance_of(_left: Val, _right: Val) -> Val { +pub fn op_instance_of(_left: Val, _right: Val) -> Result { std::panic!("Not implemented: op_instance_of"); } -pub fn op_in(_left: Val, _right: Val) -> Val { +pub fn op_in(_left: Val, _right: Val) -> Result { std::panic!("Not implemented: op_in"); } -pub fn op_sub(left: Val, right: Val) -> Val { +pub fn op_sub(left: Val, right: Val) -> Result { return match left { - Val::Void => std::panic!("Shouldn't happen"), - Val::Undefined => std::panic!("TODO: Exceptions"), - Val::Null => std::panic!("TODO: Exceptions"), - Val::Bool(_) => match right.val_to_string().as_str() { + Val::Void => format_err!("Internal: Shouldn't happen"), // TODO: Internal errors + Val::Undefined => format_err!("TypeError: Cannot subscript undefined"), + Val::Null => format_err!("TypeError: Cannot subscript null"), + Val::Bool(_) => Ok(match right.val_to_string().as_str() { "toString" => Val::Static(&BOOL_TO_STRING), "valueOf" => Val::Static(&BOOL_VALUE_OF), _ => Val::Undefined, - }, - Val::Number(number) => op_sub_number(number, &right), - Val::BigInt(bigint) => op_sub_bigint(&bigint, &right), - Val::String(string_data) => op_sub_string(&string_data, &right), + }), + Val::Number(number) => Ok(op_sub_number(number, &right)), + Val::BigInt(bigint) => Ok(op_sub_bigint(&bigint, &right)), + Val::String(string_data) => Ok(op_sub_string(&string_data, &right)), Val::Array(array_data) => { let right_index = match right.to_index() { None => { // FIXME: Inefficient val_to_string() that gets duplicated // when subscripting the object if right.val_to_string() == "length" { - return Val::Number(array_data.elements.len() as f64); + return Ok(Val::Number(array_data.elements.len() as f64)); } - return array_data.object.sub(right); + return Ok(array_data.object.sub(right)); } Some(i) => i, }; if right_index >= array_data.elements.len() { - return Val::Undefined; + return Ok(Val::Undefined); } let res = array_data.elements[right_index].clone(); - return match res { + return Ok(match res { Val::Void => Val::Undefined, _ => res, - }; + }); } - Val::Object(object_data) => { - return object_data.sub(right); - } - Val::Function(_) => Val::Undefined, - Val::Class(_) => Val::Undefined, - Val::Static(s) => s.sub(right), - Val::Custom(custom_data) => custom_data.sub(right), + Val::Object(object_data) => Ok(object_data.sub(right)), + Val::Function(_) | Val::Class(_) => Ok(Val::Undefined), + Val::Static(s) => Ok(s.sub(right)), + Val::Custom(custom_data) => Ok(custom_data.sub(right)), }; } -pub fn op_submov(target: &mut Val, subscript: Val, value: Val) { +pub fn op_submov(target: &mut Val, subscript: Val, value: Val) -> Result<(), Val> { match target { - Val::Void => std::panic!("Shouldn't happen"), - Val::Undefined => std::panic!("TODO: Exceptions"), - Val::Null => std::panic!("TODO: Exceptions"), - Val::Bool(_) => std::panic!("TODO: Exceptions"), - Val::Number(_) => std::panic!("TODO: Exceptions"), - Val::BigInt(_) => std::panic!("TODO: Exceptions"), - Val::String(_) => std::panic!("TODO: Exceptions"), + Val::Void => format_err!("Internal: Shouldn't happen"), // TODO: Internal errors + Val::Undefined => format_err!("Cannot assign to subscript of undefined"), + Val::Null => format_err!("Cannot assign to subscript of null"), + Val::Bool(_) => format_err!("Cannot assign to subscript of bool"), + Val::Number(_) => format_err!("Cannot assign to subscript of number"), + Val::BigInt(_) => format_err!("Cannot assign to subscript of bigint"), + Val::String(_) => format_err!("Cannot assign to subscript of string"), Val::Array(array_data) => { let subscript_index = match subscript.to_index() { - None => std::panic!("Not implemented: non-uint array subscript assignment"), + None => return format_err!("TODO: non-uint array subscript assignment"), Some(i) => i, }; @@ -455,7 +470,7 @@ pub fn op_submov(target: &mut Val, subscript: Val, value: Val) { array_data_mut.elements[subscript_index] = value; } else { if subscript_index - array_data_mut.elements.len() > 100 { - std::panic!("Not implemented: Sparse arrays"); + return format_err!("TODO: Sparse arrays"); } while subscript_index > array_data_mut.elements.len() { @@ -464,16 +479,20 @@ pub fn op_submov(target: &mut Val, subscript: Val, value: Val) { array_data_mut.elements.push(value); } + + Ok(()) } Val::Object(object_data) => { Rc::make_mut(object_data) .string_map .insert(subscript.val_to_string(), value); + + Ok(()) } - Val::Function(_) => std::panic!("Not implemented: function subscript assignment"), - Val::Class(_) => std::panic!("Not implemented: class subscript assignment"), - Val::Static(_) => std::panic!("TODO: Exceptions"), - Val::Custom(_) => std::panic!("Not implemented"), + Val::Function(_) => format_err!("TODO: function subscript assignment"), + Val::Class(_) => format_err!("Cannot assign to subscript of class"), + Val::Static(_) => format_err!("Cannot assign to subscript of static value"), + Val::Custom(_) => format_err!("TODO: Assign to subscript of custom value"), } } diff --git a/valuescript_vm/src/vs_array.rs b/valuescript_vm/src/vs_array.rs index 160bf9c..ec94633 100644 --- a/valuescript_vm/src/vs_array.rs +++ b/valuescript_vm/src/vs_array.rs @@ -340,7 +340,11 @@ static INCLUDES: NativeFunction = NativeFunction { let search_param = params.get(0).unwrap_or(&Val::Undefined).clone(); for elem in &array_data.elements { - if op_triple_eq_impl(elem.clone(), search_param.clone()) { + let is_eq = op_triple_eq_impl(elem.clone(), search_param.clone()) + .map_err(|e| e.val_to_string()) + .unwrap(); // TODO: Exception + + if is_eq { return Val::Bool(true); } } @@ -359,7 +363,11 @@ static INDEX_OF: NativeFunction = NativeFunction { let search_param = params.get(0).unwrap_or(&Val::Undefined).clone(); for i in 0..array_data.elements.len() { - if op_triple_eq_impl(array_data.elements[i].clone(), search_param.clone()) { + let is_eq = op_triple_eq_impl(array_data.elements[i].clone(), search_param.clone()) + .map_err(|e| e.val_to_string()) + .unwrap(); // TODO: Exception + + if is_eq { return Val::Number(i as f64); } } @@ -429,7 +437,11 @@ static LAST_INDEX_OF: NativeFunction = NativeFunction { let search_param = params.get(0).unwrap_or(&Val::Undefined).clone(); for i in (0..array_data.elements.len()).rev() { - if op_triple_eq_impl(array_data.elements[i].clone(), search_param.clone()) { + let is_eq = op_triple_eq_impl(array_data.elements[i].clone(), search_param.clone()) + .map_err(|e| e.val_to_string()) + .unwrap(); // TODO: Exception + + if is_eq { return Val::Number(i as f64); } } diff --git a/valuescript_vm/src/vs_object.rs b/valuescript_vm/src/vs_object.rs index c834ee6..cbdec17 100644 --- a/valuescript_vm/src/vs_object.rs +++ b/valuescript_vm/src/vs_object.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; -use super::vs_value::{Val, ValTrait}; use super::operations::op_sub; +use super::vs_value::{Val, ValTrait}; #[derive(Clone, Default)] pub struct VsObject { @@ -14,7 +14,9 @@ impl VsObject { return match self.string_map.get(&key.val_to_string()) { Some(val) => val.clone(), None => match &self.prototype { - Some(prototype) => op_sub(prototype.clone(), key), + Some(prototype) => op_sub(prototype.clone(), key) + .map_err(|e| e.val_to_string()) + .unwrap(), // TODO: Exception None => Val::Undefined, }, }; diff --git a/valuescript_vm/src/vs_value.rs b/valuescript_vm/src/vs_value.rs index fe98091..b081b79 100644 --- a/valuescript_vm/src/vs_value.rs +++ b/valuescript_vm/src/vs_value.rs @@ -333,11 +333,15 @@ impl ValTrait for Val { fn sub(&self, key: Val) -> Val { // TODO: Avoid cloning? - return op_sub(self.clone(), key); + op_sub(self.clone(), key) + .map_err(|e| e.val_to_string()) + .unwrap() // TODO: Exception } fn submov(&mut self, key: Val, value: Val) { - op_submov(self, key, value); + op_submov(self, key, value) + .map_err(|e| e.val_to_string()) + .unwrap() // TODO: Exception } fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {