mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-01-14 16:08:02 -05:00
Remove Vallish, use refs and clones
This commit is contained in:
@@ -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<Val>) -> Vallish<'a> {
|
||||
use Vallish::*;
|
||||
|
||||
pub fn decode_val(&mut self, registers: &Vec<Val>) -> 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<String, Val> = BTreeMap::new();
|
||||
let mut symbol_map: BTreeMap<VsSymbol, Val> = 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>) -> Val {
|
||||
return self.decode_vallish(registers).get_own();
|
||||
}
|
||||
|
||||
pub fn decode_vec_val(&mut self, registers: &Vec<Val>) -> Vec<Val> {
|
||||
let mut vals: Vec<Val> = Vec::new();
|
||||
|
||||
|
||||
@@ -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<Val, Val>,
|
||||
op: fn(left: &Val, right: &Val) -> Result<Val, Val>,
|
||||
) -> 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() {
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<bool, Val> {
|
||||
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<bool, Val> {
|
||||
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<bool, Val> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn op_eq(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
pub fn op_eq(left: &Val, right: &Val) -> Result<Val, Val> {
|
||||
Ok(Val::Bool(op_eq_impl(left, right)?))
|
||||
}
|
||||
|
||||
pub fn op_ne(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
pub fn op_ne(left: &Val, right: &Val) -> Result<Val, Val> {
|
||||
Ok(Val::Bool(!op_eq_impl(left, right)?))
|
||||
}
|
||||
|
||||
pub fn op_triple_eq_impl(left: Vallish, right: Vallish) -> Result<bool, Val> {
|
||||
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<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,
|
||||
@@ -162,7 +142,7 @@ pub fn op_triple_eq_impl(left: Vallish, right: Vallish) -> Result<bool, Val> {
|
||||
(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<bool, Val> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn op_triple_eq(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
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: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
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: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
let truthy = left.get_ref().is_truthy();
|
||||
pub fn op_and(left: &Val, right: &Val) -> Result<Val, Val> {
|
||||
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<Val, Val> {
|
||||
let truthy = left.get_ref().is_truthy();
|
||||
pub fn op_or(left: &Val, right: &Val) -> Result<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<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,
|
||||
@@ -209,7 +186,7 @@ pub fn op_less(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
(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<Val, Val> {
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn op_less_eq(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
Ok(Val::Bool(match (left.get_ref(), right.get_ref()) {
|
||||
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,
|
||||
@@ -230,8 +207,8 @@ pub fn op_less_eq(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn op_greater(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
Ok(Val::Bool(match (left.get_ref(), right.get_ref()) {
|
||||
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,
|
||||
@@ -242,8 +219,8 @@ pub fn op_greater(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn op_greater_eq(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
Ok(Val::Bool(match (left.get_ref(), right.get_ref()) {
|
||||
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,
|
||||
@@ -254,14 +231,14 @@ pub fn op_greater_eq(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn op_nullish_coalesce(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
let nullish = left.get_ref().is_nullish();
|
||||
pub fn op_nullish_coalesce(left: &Val, right: &Val) -> Result<Val, Val> {
|
||||
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<Val, Val> {
|
||||
return match left.get_ref() {
|
||||
pub fn op_optional_chain(left: &mut Val, right: &Val) -> Result<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
pub fn op_instance_of(_left: &Val, _right: &Val) -> Result<Val, Val> {
|
||||
Err("TODO: op_instance_of".to_error())
|
||||
}
|
||||
|
||||
pub fn op_in(_left: Vallish, _right: Vallish) -> Result<Val, Val> {
|
||||
pub fn op_in(_left: &Val, _right: &Val) -> Result<Val, Val> {
|
||||
Err("TODO: op_in".to_error())
|
||||
}
|
||||
|
||||
pub fn op_sub(left: Vallish, right: Vallish) -> Result<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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<Val, Val> {
|
||||
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,
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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<Val, Val> {
|
||||
// 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> {
|
||||
|
||||
Reference in New Issue
Block a user