Exceptions for binary ops

This commit is contained in:
Andrew Morris
2023-03-21 11:14:44 +11:00
parent 11b547db15
commit 215139e98b
6 changed files with 226 additions and 178 deletions

View File

@@ -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)))

View File

@@ -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<Val, Val>,
) -> 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 => {

View File

@@ -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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<bool, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
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<Val, Val> {
std::panic!("Not implemented: op_in");
}
pub fn op_sub(left: Val, right: Val) -> Val {
pub fn op_sub(left: Val, right: Val) -> Result<Val, Val> {
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"),
}
}

View File

@@ -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);
}
}

View File

@@ -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,
},
};

View File

@@ -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 {