to_val refactor, remove error macros

This commit is contained in:
Andrew Morris
2023-05-26 11:54:43 +10:00
parent 80cd4deac8
commit ea42e94d5d
36 changed files with 632 additions and 585 deletions

View File

@@ -1,9 +1,8 @@
use std::rc::Rc;
use crate::vs_value::ToVal;
use super::super::vs_value::{Val, ValTrait};
use super::super::vs_array::VsArray;
use super::super::native_frame_function::NativeFrameFunction;
use super::array_mapping_frame::{ArrayMappingState, ArrayMappingFrame};
use super::super::vs_value::{Val, ValTrait};
use super::array_mapping_frame::{ArrayMappingFrame, ArrayMappingState};
pub static FILTER: NativeFrameFunction = NativeFrameFunction {
make_frame: || Box::new(ArrayMappingFrame::new(Box::new(FilterState::default()))),
@@ -26,6 +25,6 @@ impl ArrayMappingState for FilterState {
fn finish(&mut self) -> Val {
let mut filter_results = Vec::new();
std::mem::swap(&mut self.filter_results, &mut filter_results);
return Val::Array(Rc::new(VsArray::from(filter_results)));
filter_results.to_val()
}
}

View File

@@ -1,9 +1,8 @@
use std::rc::Rc;
use crate::vs_value::ToVal;
use super::super::vs_value::{Val, ValTrait};
use super::super::vs_array::VsArray;
use super::super::native_frame_function::NativeFrameFunction;
use super::array_mapping_frame::{ArrayMappingState, ArrayMappingFrame};
use super::super::vs_value::{Val, ValTrait};
use super::array_mapping_frame::{ArrayMappingFrame, ArrayMappingState};
pub static FLAT_MAP: NativeFrameFunction = NativeFrameFunction {
make_frame: || Box::new(ArrayMappingFrame::new(Box::new(FlatMapState::default()))),
@@ -31,6 +30,6 @@ impl ArrayMappingState for FlatMapState {
fn finish(&mut self) -> Val {
let mut flat_map_results = Vec::new();
std::mem::swap(&mut self.flat_map_results, &mut flat_map_results);
return Val::Array(Rc::new(VsArray::from(flat_map_results)));
flat_map_results.to_val()
}
}

View File

@@ -1,9 +1,8 @@
use std::rc::Rc;
use crate::vs_value::ToVal;
use super::super::vs_value::{Val};
use super::super::vs_array::VsArray;
use super::super::native_frame_function::NativeFrameFunction;
use super::array_mapping_frame::{ArrayMappingState, ArrayMappingFrame};
use super::super::vs_value::Val;
use super::array_mapping_frame::{ArrayMappingFrame, ArrayMappingState};
pub static MAP: NativeFrameFunction = NativeFrameFunction {
make_frame: || Box::new(ArrayMappingFrame::new(Box::new(MapState::default()))),
@@ -23,6 +22,6 @@ impl ArrayMappingState for MapState {
fn finish(&mut self) -> Val {
let mut map_results = Vec::new();
std::mem::swap(&mut self.map_results, &mut map_results);
return Val::Array(Rc::new(VsArray::from(map_results)));
map_results.to_val()
}
}

View File

@@ -1,11 +1,11 @@
use std::rc::Rc;
use crate::builtins::type_error_builtin::ToTypeError;
use crate::native_function::ThisWrapper;
use crate::stack_frame::FrameStepResult;
use crate::stack_frame::{CallResult, FrameStepOk, StackFrameTrait};
use crate::vs_array::VsArray;
use crate::vs_value::{LoadFunctionResult, Val, ValTrait};
use crate::{builtins::type_error_builtin::to_type_error, type_error};
pub trait ArrayMappingState {
fn process(&mut self, i: usize, element: &Val, mapped: Val) -> Option<Val>;
@@ -60,7 +60,7 @@ impl StackFrameTrait for ArrayMappingFrame {
fn step(&mut self) -> FrameStepResult {
let array_data = match &self.this {
None => return type_error!("Array fn called on non-array"),
None => return Err("Array fn called on non-array".to_type_error()),
Some(ad) => ad,
};
@@ -80,9 +80,7 @@ impl StackFrameTrait for ArrayMappingFrame {
Some(el) => match el {
Val::Void => Ok(FrameStepOk::Continue),
_ => match self.mapper.load_function() {
LoadFunctionResult::NotAFunction => {
type_error!("map fn is not a function")
}
LoadFunctionResult::NotAFunction => Err("map fn is not a function".to_type_error()),
LoadFunctionResult::NativeFunction(native_fn) => {
match self.state.process(
array_i,
@@ -124,7 +122,7 @@ impl StackFrameTrait for ArrayMappingFrame {
let element = match &self.this {
None => {
self.early_exit = Some(type_error!("Array fn called on non-array"));
self.early_exit = Some(Err("Array fn called on non-array".to_type_error()));
return;
}
Some(ad) => &ad.elements[array_i],

View File

@@ -1,11 +1,11 @@
use std::rc::Rc;
use crate::builtins::type_error_builtin::ToTypeError;
use crate::native_frame_function::NativeFrameFunction;
use crate::native_function::ThisWrapper;
use crate::stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrameTrait};
use crate::vs_array::VsArray;
use crate::vs_value::{LoadFunctionResult, Val, ValTrait};
use crate::{builtins::type_error_builtin::to_type_error, type_error};
pub static REDUCE: NativeFrameFunction = NativeFrameFunction {
make_frame: || {
@@ -50,7 +50,7 @@ impl StackFrameTrait for ReduceFrame {
fn step(&mut self) -> FrameStepResult {
let array_data = match &self.this {
None => return type_error!("reduce called on non-array"),
None => return Err("reduce called on non-array".to_type_error()),
Some(ad) => ad,
};
@@ -66,7 +66,9 @@ impl StackFrameTrait for ReduceFrame {
FrameStepOk::Continue
}
Some(value) => match self.reducer.load_function() {
LoadFunctionResult::NotAFunction => return type_error!("reduce fn is not a function"),
LoadFunctionResult::NotAFunction => {
return Err("reduce fn is not a function".to_type_error())
}
LoadFunctionResult::NativeFunction(native_fn) => {
self.value = Some(native_fn(
ThisWrapper::new(true, &mut Val::Undefined),
@@ -91,7 +93,7 @@ impl StackFrameTrait for ReduceFrame {
},
},
None => match &self.value {
None => return type_error!("reduce of empty array with no initial value"),
None => return Err("reduce of empty array with no initial value".to_type_error()),
Some(value) => FrameStepOk::Pop(CallResult {
return_: value.clone(),
this: Val::Array(array_data.clone()),

View File

@@ -1,11 +1,11 @@
use std::rc::Rc;
use crate::builtins::type_error_builtin::ToTypeError;
use crate::native_frame_function::NativeFrameFunction;
use crate::native_function::ThisWrapper;
use crate::stack_frame::{CallResult, FrameStepOk, FrameStepResult, StackFrameTrait};
use crate::vs_array::VsArray;
use crate::vs_value::{LoadFunctionResult, Val, ValTrait};
use crate::{builtins::type_error_builtin::to_type_error, format_err, type_error};
pub static REDUCE_RIGHT: NativeFrameFunction = NativeFrameFunction {
make_frame: || {
@@ -56,14 +56,14 @@ impl StackFrameTrait for ReduceRightFrame {
fn step(&mut self) -> FrameStepResult {
let array_data = match &self.this {
None => return type_error!("reduceRight called on non-array"),
None => return Err("reduceRight called on non-array".to_type_error()),
Some(ad) => ad,
};
if self.array_i == 0 {
match &self.value {
None => {
return type_error!("reduceRight of empty array with no initial value");
return Err("reduceRight of empty array with no initial value".to_type_error());
}
Some(value) => {
return Ok(FrameStepOk::Pop(CallResult {
@@ -88,7 +88,7 @@ impl StackFrameTrait for ReduceRightFrame {
}
Some(value) => match self.reducer.load_function() {
LoadFunctionResult::NotAFunction => {
return format_err!("TpeError: reduceRight fn is not a function")
return Err("reduceRight fn is not a function".to_type_error())
}
LoadFunctionResult::NativeFunction(native_fn) => {
self.value = Some(native_fn(

View File

@@ -1,12 +1,12 @@
use std::rc::Rc;
use crate::builtins::type_error_builtin::ToTypeError;
use crate::native_frame_function::NativeFrameFunction;
use crate::native_function::ThisWrapper;
use crate::stack_frame::FrameStepResult;
use crate::stack_frame::{CallResult, FrameStepOk, StackFrameTrait};
use crate::vs_array::VsArray;
use crate::vs_value::{LoadFunctionResult, Val, ValTrait};
use crate::{builtins::type_error_builtin::to_type_error, type_error};
use crate::vs_value::{LoadFunctionResult, ToVal, Val, ValTrait};
pub static SORT: NativeFrameFunction = NativeFrameFunction {
make_frame: || {
@@ -208,7 +208,7 @@ enum SortTreeNodeData {
impl StackFrameTrait for SortFrame {
fn write_this(&mut self, const_: bool, this: Val) -> Result<(), Val> {
if const_ {
return type_error!("Cannot sort const array");
return Err("Cannot sort const array".to_type_error());
}
self.this = this.as_array_data();
@@ -229,7 +229,7 @@ impl StackFrameTrait for SortFrame {
fn step(&mut self) -> FrameStepResult {
if !self.started {
let array_data = match &mut self.this {
None => return type_error!("array fn called on non-array"),
None => return Err("array fn called on non-array".to_type_error()),
Some(ad) => ad,
};
@@ -263,7 +263,7 @@ impl StackFrameTrait for SortFrame {
SortTreeNodeData::Sorted(vals) => {
let mut owned_vals = vec![];
std::mem::swap(&mut owned_vals, vals);
let res = Val::Array(Rc::new(VsArray::from(owned_vals)));
let res = owned_vals.to_val();
FrameStepOk::Pop(CallResult {
return_: res.clone(),
@@ -274,7 +274,7 @@ impl StackFrameTrait for SortFrame {
},
Some((left, right)) => match self.comparator.load_function() {
LoadFunctionResult::NotAFunction => {
return type_error!("comparator is not a function");
return Err("comparator is not a function".to_type_error());
}
LoadFunctionResult::NativeFunction(native_fn) => {
let res = native_fn(

View File

@@ -1,12 +1,10 @@
use std::rc::Rc;
use num_bigint::BigInt;
use crate::{
format_err,
builtins::error_builtin::ToError,
native_function::{NativeFunction, ThisWrapper},
todo_fn::TODO,
vs_value::{Val, ValTrait},
vs_value::{ToValString, Val, ValTrait},
};
pub fn op_sub_bigint(_bigint: &BigInt, subscript: &Val) -> Val {
@@ -23,12 +21,12 @@ static TO_STRING: NativeFunction = NativeFunction {
Ok(match this.get() {
Val::BigInt(_) => match params.get(0) {
Some(_) => {
return format_err!("TODO: toString with radix");
return Err("TODO: toString with radix".to_error());
}
None => Val::String(Rc::new(this.get().val_to_string())),
None => this.get().to_val_string(),
},
_ => return format_err!("TODO: bigint indirection"),
_ => return Err("TODO: bigint indirection".to_error()),
})
},
};
@@ -37,7 +35,7 @@ static VALUE_OF: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
Val::BigInt(bigint) => Val::BigInt(bigint.clone()),
_ => return format_err!("TODO: bigint indirection"),
_ => return Err("TODO: bigint indirection".to_error()),
})
},
};

View File

@@ -4,18 +4,18 @@ use num_bigint::BigInt;
use crate::{
builtins::range_error_builtin::to_range_error,
builtins::type_error_builtin::to_type_error,
format_err,
native_function::{NativeFunction, ThisWrapper},
operations::op_sub,
range_error, type_error,
range_error,
vs_array::VsArray,
vs_class::VsClass,
vs_object::VsObject,
vs_value::{LoadFunctionResult, Val, VsType},
vs_value::{LoadFunctionResult, ToVal, ToValString, Val, VsType},
ValTrait,
};
use super::type_error_builtin::ToTypeError;
pub struct ArrayBuiltin {}
pub static ARRAY_BUILTIN: ArrayBuiltin = ArrayBuiltin {};
@@ -37,7 +37,7 @@ impl ValTrait for ArrayBuiltin {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new("function Array() { [native code] }".to_string()))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -75,7 +75,7 @@ impl ValTrait for ArrayBuiltin {
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of Array builtin")
Err("Cannot assign to subscript of Array builtin".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {
@@ -106,36 +106,31 @@ static IS_ARRAY: NativeFunction = NativeFunction {
static FROM: NativeFunction = NativeFunction {
fn_: |_this: ThisWrapper, params: Vec<Val>| -> Result<Val, Val> {
let first_param = match params.get(0) {
None => return type_error!("undefined is not iterable"),
None => return Err("undefined is not iterable".to_type_error()),
Some(p) => p,
};
if params.len() > 1 {
return format_err!("TODO: Using Array.from with a map function");
return Err(format!("TODO: Using Array.from with a map function").to_val());
}
Ok(match first_param {
Val::Array(arr) => Val::Array(arr.clone()),
Val::String(s) => Val::Array(Rc::new(VsArray::from(
s.chars()
.map(|c| Val::String(Rc::new(c.to_string())))
.collect(),
))),
Val::Void | Val::Undefined | Val::Null => return type_error!("items is not iterable"),
Val::String(s) => s.chars().map(|c| c.to_val()).collect::<Vec<Val>>().to_val(),
Val::Void | Val::Undefined | Val::Null => {
return Err("items is not iterable".to_type_error())
}
Val::Bool(..) | Val::Number(..) | Val::BigInt(..) | Val::Symbol(..) => {
Val::Array(Rc::new(VsArray::new()))
VsArray::new().to_val()
}
Val::Object(..) | Val::Function(..) | Val::Class(..) | Val::Static(..) | Val::Custom(..) => {
let len = op_sub(
first_param.clone(),
Val::String(Rc::new("length".to_string())),
)
.map_err(|e| e.val_to_string())
.unwrap() // TODO: Exception
.to_number();
let len = op_sub(first_param.clone(), "length".to_val())
.map_err(|e| e.val_to_string())
.unwrap() // TODO: Exception
.to_number();
if len.is_sign_negative() || len.is_nan() {
return Ok(Val::Array(Rc::new(VsArray::new())));
return Ok(VsArray::new().to_val());
}
if len.is_infinite() {
@@ -156,7 +151,7 @@ static FROM: NativeFunction = NativeFunction {
);
}
Val::Array(Rc::new(VsArray::from(arr)))
VsArray::from(arr).to_val()
}
})
},
@@ -164,13 +159,13 @@ static FROM: NativeFunction = NativeFunction {
static OF: NativeFunction = NativeFunction {
fn_: |_this: ThisWrapper, params: Vec<Val>| -> Result<Val, Val> {
Ok(Val::Array(Rc::new(VsArray::from(params))))
Ok(VsArray::from(params).to_val())
},
};
fn to_array(_: ThisWrapper, params: Vec<Val>) -> Result<Val, Val> {
if params.len() != 1 {
return Ok(Val::Array(Rc::new(VsArray::from(params))));
return Ok(VsArray::from(params).to_val());
}
Ok(match params[0] {
@@ -187,8 +182,8 @@ fn to_array(_: ThisWrapper, params: Vec<Val>) -> Result<Val, Val> {
arr.push(Val::Void);
}
Val::Array(Rc::new(VsArray::from(arr)))
VsArray::from(arr).to_val()
}
_ => Val::Array(Rc::new(VsArray::from(params))),
_ => VsArray::from(params).to_val(),
})
}

View File

@@ -3,16 +3,16 @@ use std::rc::Rc;
use num_bigint::BigInt;
use crate::{
builtins::type_error_builtin::to_type_error,
native_function::ThisWrapper,
type_error,
vs_array::VsArray,
vs_class::VsClass,
vs_object::VsObject,
vs_value::{LoadFunctionResult, Val, VsType},
vs_value::{LoadFunctionResult, ToValString, Val, VsType},
ValTrait,
};
use super::type_error_builtin::ToTypeError;
pub struct BooleanBuiltin {}
pub static BOOLEAN_BUILTIN: BooleanBuiltin = BooleanBuiltin {};
@@ -34,7 +34,7 @@ impl ValTrait for BooleanBuiltin {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new("function Boolean() { [native code] }".to_string()))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -67,7 +67,7 @@ impl ValTrait for BooleanBuiltin {
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of Boolean builtin")
Err("Cannot assign to subscript of Boolean builtin".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {

View File

@@ -6,8 +6,9 @@ use crate::native_function::{NativeFunction, ThisWrapper};
use crate::vs_array::VsArray;
use crate::vs_class::VsClass;
use crate::vs_object::VsObject;
use crate::vs_value::{LoadFunctionResult, Val, ValTrait, VsType};
use crate::{builtins::type_error_builtin::to_type_error, type_error};
use crate::vs_value::{LoadFunctionResult, ToValString, Val, ValTrait, VsType};
use super::type_error_builtin::ToTypeError;
pub struct DebugBuiltin {}
@@ -30,7 +31,7 @@ impl ValTrait for DebugBuiltin {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new(self.val_to_string()))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -69,7 +70,7 @@ impl ValTrait for DebugBuiltin {
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of Debug builtin")
Err("Cannot assign to subscript of Debug builtin".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {

View File

@@ -3,9 +3,8 @@ use std::{collections::BTreeMap, rc::Rc};
use num_bigint::BigInt;
use crate::native_function::ThisWrapper;
use crate::{builtins::type_error_builtin::to_type_error, type_error};
use crate::vs_value::{ToVal, ToValString};
use crate::{
format_val,
native_function::NativeFunction,
operations::{op_sub, op_submov},
vs_array::VsArray,
@@ -15,6 +14,8 @@ use crate::{
ValTrait,
};
use super::type_error_builtin::ToTypeError;
pub struct ErrorBuiltin {}
pub static ERROR_BUILTIN: ErrorBuiltin = ErrorBuiltin {};
@@ -36,7 +37,7 @@ impl ValTrait for ErrorBuiltin {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new("function Error() { [native code] }".to_string()))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -64,7 +65,15 @@ impl ValTrait for ErrorBuiltin {
}
fn load_function(&self) -> LoadFunctionResult {
LoadFunctionResult::NativeFunction(to_error)
LoadFunctionResult::NativeFunction(|_: ThisWrapper, params: Vec<Val>| -> Result<Val, Val> {
Ok(
match params.get(0) {
Some(param) => param.to_val_string(),
None => "".to_val(),
}
.to_error(),
)
})
}
fn sub(&self, _key: Val) -> Result<Val, Val> {
@@ -72,7 +81,7 @@ impl ValTrait for ErrorBuiltin {
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of Error builtin")
Err("Cannot assign to subscript of Error builtin".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {
@@ -88,44 +97,44 @@ impl ValTrait for ErrorBuiltin {
}
}
#[macro_export]
macro_rules! error {
($fmt:expr $(, $($arg:expr),*)?) => {{
let formatted_string = format!($fmt $(, $($arg),*)?);
Err(to_error(
ThisWrapper::new(true, &mut Val::Undefined),
vec![Val::String(Rc::new(formatted_string))],
).unwrap())
}};
pub trait ToError {
fn to_error(self) -> Val;
}
pub fn to_error(_: ThisWrapper, params: Vec<Val>) -> Result<Val, Val> {
Ok(Val::Object(Rc::new(VsObject {
string_map: BTreeMap::from([(
"message".to_string(),
Val::String(Rc::new(match params.get(0) {
Some(param) => param.val_to_string(),
None => "".to_string(),
})),
)]),
symbol_map: Default::default(),
prototype: Some(make_error_prototype()),
})))
impl ToError for Val {
fn to_error(self) -> Val {
VsObject {
string_map: BTreeMap::from([("message".to_string(), self.to_val_string())]),
symbol_map: Default::default(),
prototype: Some(make_error_prototype()),
}
.to_val()
}
}
impl ToError for String {
fn to_error(self) -> Val {
self.to_val().to_error()
}
}
impl ToError for &str {
fn to_error(self) -> Val {
self.to_string().to_error()
}
}
// TODO: Static? (Rc -> Arc?)
fn make_error_prototype() -> Val {
Val::Object(Rc::new(VsObject {
VsObject {
string_map: BTreeMap::from([
(
"name".to_string(),
Val::String(Rc::new("Error".to_string())),
),
("toString".to_string(), Val::Static(&ERROR_TO_STRING)),
("name".to_string(), "Error".to_val()),
("toString".to_string(), ERROR_TO_STRING.to_val()),
]),
symbol_map: Default::default(),
prototype: None,
}))
}
.to_val()
}
static SET_MESSAGE: NativeFunction = NativeFunction {
@@ -135,11 +144,7 @@ static SET_MESSAGE: NativeFunction = NativeFunction {
None => "".to_string(),
};
op_submov(
this.get_mut()?,
format_val!("message"),
format_val!("{}", message),
)?;
op_submov(this.get_mut()?, "message".to_val(), message.to_val())?;
Ok(Val::Undefined)
},
@@ -147,7 +152,7 @@ static SET_MESSAGE: NativeFunction = NativeFunction {
static ERROR_TO_STRING: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
let message = op_sub(this.get().clone(), format_val!("message"))?;
Ok(format_val!("Error({})", message)) // TODO: Fixes needed here (and other errors)
let message = op_sub(this.get().clone(), "message".to_val())?;
Ok(format!("Error({})", message).to_val()) // TODO: Fixes needed here (and other errors)
},
};

View File

@@ -7,8 +7,9 @@ use crate::operations::to_u32;
use crate::vs_array::VsArray;
use crate::vs_class::VsClass;
use crate::vs_object::VsObject;
use crate::vs_value::{LoadFunctionResult, Val, ValTrait, VsType};
use crate::{builtins::type_error_builtin::to_type_error, type_error};
use crate::vs_value::{LoadFunctionResult, ToValString, Val, ValTrait, VsType};
use super::type_error_builtin::ToTypeError;
pub struct MathBuiltin {}
@@ -31,7 +32,7 @@ impl ValTrait for MathBuiltin {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new(self.val_to_string()))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -114,7 +115,7 @@ impl ValTrait for MathBuiltin {
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of Math builtin")
Err("Cannot assign to subscript of Math builtin".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {

View File

@@ -3,7 +3,7 @@ use std::rc::Rc;
use num_bigint::BigInt;
use crate::native_function::ThisWrapper;
use crate::{builtins::type_error_builtin::to_type_error, type_error};
use crate::vs_value::ToValString;
use crate::{
native_function::NativeFunction,
vs_array::VsArray,
@@ -13,6 +13,8 @@ use crate::{
ValTrait,
};
use super::type_error_builtin::ToTypeError;
pub struct NumberBuiltin {}
pub static NUMBER_BUILTIN: NumberBuiltin = NumberBuiltin {};
@@ -34,7 +36,7 @@ impl ValTrait for NumberBuiltin {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new("function Number() { [native code] }".to_string()))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -83,7 +85,7 @@ impl ValTrait for NumberBuiltin {
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of Number builtin")
Err("Cannot assign to subscript of Number builtin".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {

View File

@@ -3,9 +3,8 @@ use std::{collections::BTreeMap, rc::Rc};
use num_bigint::BigInt;
use crate::native_function::ThisWrapper;
use crate::{builtins::type_error_builtin::to_type_error, type_error};
use crate::vs_value::{ToVal, ToValString};
use crate::{
format_val,
native_function::NativeFunction,
operations::{op_sub, op_submov},
vs_array::VsArray,
@@ -15,6 +14,8 @@ use crate::{
ValTrait,
};
use super::type_error_builtin::ToTypeError;
pub struct RangeErrorBuiltin {}
pub static RANGE_ERROR_BUILTIN: RangeErrorBuiltin = RangeErrorBuiltin {};
@@ -36,9 +37,7 @@ impl ValTrait for RangeErrorBuiltin {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new(
"function RangeError() { [native code] }".to_string(),
))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -74,7 +73,7 @@ impl ValTrait for RangeErrorBuiltin {
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of RangeError builtin")
Err("Cannot assign to subscript of RangeError builtin".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {
@@ -91,32 +90,33 @@ impl ValTrait for RangeErrorBuiltin {
}
pub fn to_range_error(_: ThisWrapper, params: Vec<Val>) -> Result<Val, Val> {
Ok(Val::Object(Rc::new(VsObject {
string_map: BTreeMap::from([(
"message".to_string(),
Val::String(Rc::new(match params.get(0) {
Some(param) => param.val_to_string(),
None => "".to_string(),
})),
)]),
symbol_map: Default::default(),
prototype: Some(make_range_error_prototype()),
})))
Ok(
VsObject {
string_map: BTreeMap::from([(
"message".to_string(),
match params.get(0) {
Some(param) => param.to_val_string(),
None => "".to_val(),
},
)]),
symbol_map: Default::default(),
prototype: Some(make_range_error_prototype()),
}
.to_val(),
)
}
// TODO: Static? (Rc -> Arc?)
fn make_range_error_prototype() -> Val {
Val::Object(Rc::new(VsObject {
VsObject {
string_map: BTreeMap::from([
(
"name".to_string(),
Val::String(Rc::new("RangeError".to_string())),
),
("name".to_string(), "RangeError".to_val()),
("toString".to_string(), Val::Static(&RANGE_ERROR_TO_STRING)),
]),
symbol_map: Default::default(),
prototype: None,
}))
}
.to_val()
}
static SET_MESSAGE: NativeFunction = NativeFunction {
@@ -126,11 +126,7 @@ static SET_MESSAGE: NativeFunction = NativeFunction {
None => "".to_string(),
};
op_submov(
this.get_mut()?,
format_val!("message"),
format_val!("{}", message),
)?;
op_submov(this.get_mut()?, "message".to_val(), message.to_val())?;
Ok(Val::Undefined)
},
@@ -138,8 +134,8 @@ static SET_MESSAGE: NativeFunction = NativeFunction {
static RANGE_ERROR_TO_STRING: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
let message = op_sub(this.get().clone(), format_val!("message"))?;
Ok(format_val!("RangeError({})", message))
let message = op_sub(this.get().clone(), "message".to_val())?;
Ok(format!("RangeError({})", message).to_val())
},
};
@@ -149,7 +145,7 @@ macro_rules! range_error {
let formatted_string = format!($fmt $(, $($arg),*)?);
Err(to_range_error(
ThisWrapper::new(true, &mut Val::Undefined),
vec![Val::String(Rc::new(formatted_string))],
vec![formatted_string.to_val()],
).unwrap())
}};
}

View File

@@ -3,8 +3,8 @@ use std::rc::Rc;
use num_bigint::BigInt;
use crate::native_function::ThisWrapper;
use crate::vs_value::{ToVal, ToValString};
use crate::{builtins::range_error_builtin::to_range_error, range_error};
use crate::{builtins::type_error_builtin::to_type_error, type_error};
use crate::{
native_function::NativeFunction,
vs_array::VsArray,
@@ -14,6 +14,8 @@ use crate::{
ValTrait,
};
use super::type_error_builtin::ToTypeError;
pub struct StringBuiltin {}
pub static STRING_BUILTIN: StringBuiltin = StringBuiltin {};
@@ -35,7 +37,7 @@ impl ValTrait for StringBuiltin {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new("function String() { [native code] }".to_string()))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -76,7 +78,7 @@ impl ValTrait for StringBuiltin {
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of String builtin")
Err("Cannot assign to subscript of String builtin".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {
@@ -107,14 +109,14 @@ static FROM_CODE_POINT: NativeFunction = NativeFunction {
result.push(char);
}
Ok(Val::String(Rc::new(result)))
Ok(result.to_val())
},
};
fn to_string(_: ThisWrapper, params: Vec<Val>) -> Result<Val, Val> {
Ok(if let Some(value) = params.get(0) {
Val::String(Rc::new(value.val_to_string()))
value.to_val_string()
} else {
Val::String(Rc::new("".to_string()))
"".to_val()
})
}

View File

@@ -3,17 +3,16 @@ use std::rc::Rc;
use num_bigint::BigInt;
use crate::{
builtins::type_error_builtin::to_type_error,
native_function::ThisWrapper,
type_error,
vs_array::VsArray,
vs_class::VsClass,
vs_object::VsObject,
vs_symbol::VsSymbol,
vs_value::{LoadFunctionResult, Val, VsType},
vs_value::{LoadFunctionResult, ToValString, Val, VsType},
ValTrait,
};
use super::type_error_builtin::ToTypeError;
pub struct SymbolBuiltin {}
pub static SYMBOL_BUILTIN: SymbolBuiltin = SymbolBuiltin {};
@@ -35,7 +34,7 @@ impl ValTrait for SymbolBuiltin {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new("[object Symbol]".to_string()))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -71,7 +70,7 @@ impl ValTrait for SymbolBuiltin {
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of Symbol builtin")
Err("Cannot assign to subscript of Symbol builtin".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {

View File

@@ -3,9 +3,8 @@ use std::{collections::BTreeMap, rc::Rc};
use num_bigint::BigInt;
use crate::native_function::ThisWrapper;
use crate::type_error;
use crate::vs_value::{ToVal, ToValString};
use crate::{
format_val,
native_function::NativeFunction,
operations::{op_sub, op_submov},
vs_array::VsArray,
@@ -36,9 +35,7 @@ impl ValTrait for TypeErrorBuiltin {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new(
"function TypeError() { [native code] }".to_string(),
))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -66,7 +63,15 @@ impl ValTrait for TypeErrorBuiltin {
}
fn load_function(&self) -> LoadFunctionResult {
LoadFunctionResult::NativeFunction(to_type_error)
LoadFunctionResult::NativeFunction(|_: ThisWrapper, params: Vec<Val>| -> Result<Val, Val> {
Ok(
match params.get(0) {
Some(param) => param.to_val_string(),
None => "".to_val(),
}
.to_type_error(),
)
})
}
fn sub(&self, _key: Val) -> Result<Val, Val> {
@@ -74,7 +79,7 @@ impl ValTrait for TypeErrorBuiltin {
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of TypeError builtin")
Err("Cannot assign to subscript of TypeError builtin".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {
@@ -90,33 +95,17 @@ impl ValTrait for TypeErrorBuiltin {
}
}
pub fn to_type_error(_: ThisWrapper, params: Vec<Val>) -> Result<Val, Val> {
Ok(Val::Object(Rc::new(VsObject {
string_map: BTreeMap::from([(
"message".to_string(),
Val::String(Rc::new(match params.get(0) {
Some(param) => param.val_to_string(),
None => "".to_string(),
})),
)]),
symbol_map: Default::default(),
prototype: Some(make_type_error_prototype()),
})))
}
// TODO: Static? (Rc -> Arc?)
fn make_type_error_prototype() -> Val {
Val::Object(Rc::new(VsObject {
VsObject {
string_map: BTreeMap::from([
(
"name".to_string(),
Val::String(Rc::new("TypeError".to_string())),
),
("toString".to_string(), Val::Static(&TYPE_ERROR_TO_STRING)),
("name".to_string(), "TypeError".to_val()),
("toString".to_string(), TYPE_ERROR_TO_STRING.to_val()),
]),
symbol_map: Default::default(),
prototype: None,
}))
}
.to_val()
}
static SET_MESSAGE: NativeFunction = NativeFunction {
@@ -126,11 +115,7 @@ static SET_MESSAGE: NativeFunction = NativeFunction {
None => "".to_string(),
};
op_submov(
this.get_mut()?,
format_val!("message"),
format_val!("{}", message),
)?;
op_submov(this.get_mut()?, "message".to_val(), message.to_val())?;
Ok(Val::Undefined)
},
@@ -138,18 +123,34 @@ static SET_MESSAGE: NativeFunction = NativeFunction {
static TYPE_ERROR_TO_STRING: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
let message = op_sub(this.get().clone(), format_val!("message"))?;
Ok(format_val!("TypeError({})", message))
let message = op_sub(this.get().clone(), "message".to_val())?;
Ok(format!("TypeError({})", message).to_val())
},
};
#[macro_export]
macro_rules! type_error {
($fmt:expr $(, $($arg:expr),*)?) => {{
let formatted_string = format!($fmt $(, $($arg),*)?);
Err(to_type_error(
ThisWrapper::new(true, &mut Val::Undefined),
vec![Val::String(Rc::new(formatted_string))],
).unwrap())
}};
pub trait ToTypeError {
fn to_type_error(self) -> Val;
}
impl ToTypeError for &str {
fn to_type_error(self) -> Val {
self.to_string().to_type_error()
}
}
impl ToTypeError for String {
fn to_type_error(self) -> Val {
self.to_val().to_type_error()
}
}
impl ToTypeError for Val {
fn to_type_error(self) -> Val {
VsObject {
string_map: BTreeMap::from([("message".to_string(), self)]),
symbol_map: Default::default(),
prototype: Some(make_type_error_prototype()),
}
.to_val()
}
}

View File

@@ -6,12 +6,12 @@ use num_bigint::Sign;
use valuescript_common::InstructionByte;
use crate::builtins::BUILTIN_VALS;
use crate::vs_array::VsArray;
use crate::vs_class::VsClass;
use crate::vs_function::VsFunction;
use crate::vs_object::VsObject;
use crate::vs_pointer::VsPointer;
use crate::vs_symbol::VsSymbol;
use crate::vs_value::ToVal;
use crate::vs_value::Val;
use crate::vs_value::ValTrait;
@@ -100,9 +100,9 @@ impl BytecodeDecoder {
BytecodeType::Null => Val::Null,
BytecodeType::False => Val::Bool(false),
BytecodeType::True => Val::Bool(true),
BytecodeType::SignedByte => Val::Number(self.decode_signed_byte() as f64),
BytecodeType::Number => Val::Number(self.decode_number()),
BytecodeType::String => Val::String(Rc::new(self.decode_string())),
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 => {
let mut vals: Vec<Val> = Vec::new();
@@ -112,7 +112,7 @@ impl BytecodeDecoder {
self.decode_type(); // End (TODO: assert)
Val::Array(Rc::new(VsArray::from(vals)))
vals.to_val()
}
BytecodeType::Object => {
let mut string_map: BTreeMap<String, Val> = BTreeMap::new();
@@ -131,11 +131,12 @@ impl BytecodeDecoder {
self.decode_type(); // End (TODO: assert)
Val::Object(Rc::new(VsObject {
VsObject {
string_map,
symbol_map,
prototype: None,
}))
}
.to_val()
}
BytecodeType::Function => self.decode_function_header(),
BytecodeType::Pointer => self.decode_pointer(),
@@ -144,11 +145,12 @@ impl BytecodeDecoder {
val => val,
},
BytecodeType::Builtin => Val::Static(BUILTIN_VALS[self.decode_varsize_uint()]),
BytecodeType::Class => Val::Class(Rc::new(VsClass {
BytecodeType::Class => VsClass {
constructor: self.decode_val(registers),
instance_prototype: self.decode_val(registers),
})),
BytecodeType::BigInt => Val::BigInt(self.decode_bigint()),
}
.to_val(),
BytecodeType::BigInt => self.decode_bigint().to_val(),
BytecodeType::Unrecognized => panic!("Unrecognized bytecode type at {}", self.pos - 1),
};
}
@@ -249,7 +251,7 @@ impl BytecodeDecoder {
}
}
return VsPointer::new(&self.data, pos);
VsPointer::new(&self.data, pos).to_val()
}
pub fn decode_function_header(&mut self) -> Val {
@@ -257,13 +259,14 @@ impl BytecodeDecoder {
let register_count = self.decode_byte() as usize;
let parameter_count = self.decode_byte() as usize;
return Val::Function(Rc::new(VsFunction {
return VsFunction {
bytecode: self.data.clone(),
register_count: register_count,
parameter_count: parameter_count,
register_count,
parameter_count,
start: self.pos,
binds: Vec::new(),
}));
}
.to_val();
}
pub fn decode_instruction(&mut self) -> InstructionByte {

View File

@@ -1,8 +1,6 @@
use std::rc::Rc;
use valuescript_common::InstructionByte;
use crate::builtins::type_error_builtin::to_type_error;
use crate::builtins::type_error_builtin::ToTypeError;
use crate::bytecode_decoder::BytecodeDecoder;
use crate::bytecode_decoder::BytecodeType;
use crate::native_function::ThisWrapper;
@@ -10,8 +8,8 @@ use crate::operations;
use crate::stack_frame::FrameStepOk;
use crate::stack_frame::FrameStepResult;
use crate::stack_frame::{CallResult, StackFrame, StackFrameTrait};
use crate::type_error;
use crate::vs_object::VsObject;
use crate::vs_value::ToVal;
use crate::vs_value::{LoadFunctionResult, Val, ValTrait};
pub struct BytecodeStackFrame {
@@ -371,15 +369,16 @@ impl StackFrameTrait for BytecodeStackFrame {
let class = match self.decoder.decode_val(&self.registers).as_class_data() {
Some(class) => class,
None => {
return type_error!("value is not a constructor");
return Err("value is not a constructor".to_type_error());
}
};
let mut instance = Val::Object(Rc::new(VsObject {
let mut instance = VsObject {
string_map: Default::default(),
symbol_map: Default::default(),
prototype: Some(class.instance_prototype.clone()),
}));
}
.to_val();
match class.constructor {
Val::Void => {
@@ -456,7 +455,7 @@ impl StackFrameTrait for BytecodeStackFrame {
RequireMutableThis => {
if self.const_this {
return type_error!("Cannot mutate this because it is const");
return Err("Cannot mutate this because it is const".to_type_error());
}
}
};

View File

@@ -5,7 +5,6 @@ mod bytecode_decoder;
mod bytecode_stack_frame;
mod first_stack_frame;
mod helpers;
mod macros;
mod native_frame_function;
mod native_function;
mod number_methods;

View File

@@ -1,17 +0,0 @@
#[macro_export]
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_export]
macro_rules! format_val {
($fmt:expr $(, $($arg:expr),*)?) => {{
let formatted_string = format!($fmt $(, $($arg),*)?);
Val::String(Rc::new(formatted_string))
}};
}

View File

@@ -2,14 +2,13 @@ use std::rc::Rc;
use num_bigint::BigInt;
use crate::format_err;
use crate::native_function::ThisWrapper;
use crate::builtins::error_builtin::ToError;
use crate::builtins::type_error_builtin::ToTypeError;
use crate::stack_frame::StackFrame;
use crate::vs_array::VsArray;
use crate::vs_class::VsClass;
use crate::vs_object::VsObject;
use crate::vs_value::{LoadFunctionResult, Val, ValTrait, VsType};
use crate::{builtins::type_error_builtin::to_type_error, type_error};
use crate::vs_value::{LoadFunctionResult, ToValString, Val, ValTrait, VsType};
pub struct NativeFrameFunction {
pub make_frame: fn() -> StackFrame,
@@ -32,7 +31,7 @@ impl ValTrait for NativeFrameFunction {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new(self.val_to_string()))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -63,11 +62,11 @@ impl ValTrait for NativeFrameFunction {
}
fn sub(&self, _key: Val) -> Result<Val, Val> {
format_err!("TODO: Subscript native function")
Err("TODO: Subscript native function".to_error())
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of native function")
Err("Cannot assign to subscript of native function".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {

View File

@@ -2,12 +2,12 @@ use std::rc::Rc;
use num_bigint::BigInt;
use crate::format_err;
use crate::builtins::error_builtin::ToError;
use crate::builtins::type_error_builtin::ToTypeError;
use crate::vs_array::VsArray;
use crate::vs_class::VsClass;
use crate::vs_object::VsObject;
use crate::vs_value::{LoadFunctionResult, Val, ValTrait, VsType};
use crate::{builtins::type_error_builtin::to_type_error, type_error};
use crate::vs_value::{LoadFunctionResult, ToVal, ToValString, Val, ValTrait, VsType};
pub struct ThisWrapper<'a> {
const_: bool,
@@ -25,7 +25,7 @@ impl<'a> ThisWrapper<'a> {
pub fn get_mut(&mut self) -> Result<&mut Val, Val> {
if self.const_ {
return type_error!("Cannot mutate this because it is const");
return Err("Cannot mutate this because it is const".to_type_error());
}
Ok(self.this)
@@ -53,7 +53,7 @@ impl ValTrait for NativeFunction {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new(self.val_to_string()))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -84,11 +84,11 @@ impl ValTrait for NativeFunction {
}
fn sub(&self, _key: Val) -> Result<Val, Val> {
format_err!("TODO: Subscript native function")
Err("TODO: Subscript native function".to_error())
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of native function")
Err("Cannot assign to subscript of native function".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {
@@ -103,3 +103,9 @@ impl ValTrait for NativeFunction {
"function() { [native code] }".into()
}
}
impl ToVal for &'static NativeFunction {
fn to_val(self) -> Val {
Val::Static(self)
}
}

View File

@@ -1,9 +1,8 @@
use std::rc::Rc;
use crate::builtins::error_builtin::ToError;
use crate::native_function::ThisWrapper;
use crate::vs_value::{ToVal, ToValString};
use crate::{builtins::range_error_builtin::to_range_error, range_error};
use crate::{
format_err, format_val,
native_function::NativeFunction,
todo_fn::TODO,
vs_value::{Val, ValTrait},
@@ -26,16 +25,19 @@ static TO_FIXED: NativeFunction = NativeFunction {
Ok(match this.get() {
Val::Number(number) => {
if number.is_infinite() {
return Ok(if number.is_sign_positive() {
Val::String(Rc::new("Infinity".to_string()))
} else {
Val::String(Rc::new("-Infinity".to_string()))
});
return Ok(
if number.is_sign_positive() {
"Infinity"
} else {
"-Infinity"
}
.to_val(),
);
}
let mut precision = match params.get(0) {
Some(p) => p.to_number(),
_ => return Ok(Val::String(Rc::new(this.get().val_to_string()))),
_ => return Ok(this.get().to_val_string()),
};
precision = f64::floor(precision);
@@ -44,9 +46,9 @@ static TO_FIXED: NativeFunction = NativeFunction {
return range_error!("precision must be between 1 and 100");
}
format_val!("{:.*}", precision as usize, number)
format!("{:.*}", precision as usize, number).to_val()
}
_ => return format_err!("TODO: number indirection"),
_ => return Err(format!("TODO: number indirection").to_val()),
})
},
};
@@ -67,7 +69,7 @@ static TO_EXPONENTIAL: NativeFunction = NativeFunction {
}
None => format_exponential(*number, None),
},
_ => return format_err!("number indirection"),
_ => return Err("number indirection".to_error()),
})
},
};
@@ -75,8 +77,8 @@ static TO_EXPONENTIAL: NativeFunction = NativeFunction {
static TODO_LOCALE: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
match this.get() {
Val::Number(_number) => return format_err!("TODO: locale"),
_ => return format_err!("number indirection"),
Val::Number(_number) => return Err("TODO: locale".to_error()),
_ => return Err("number indirection".to_error()),
}
},
};
@@ -86,12 +88,12 @@ static TO_STRING: NativeFunction = NativeFunction {
Ok(match this.get() {
Val::Number(_) => match params.get(0) {
Some(_) => {
return format_err!("TODO: toString with radix");
return Err("TODO: toString with radix".to_error());
}
None => Val::String(Rc::new(this.get().val_to_string())),
None => this.get().to_val_string(),
},
_ => return format_err!("number indirection"),
_ => return Err("number indirection".to_error()),
})
},
};
@@ -100,7 +102,7 @@ static VALUE_OF: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
Val::Number(number) => Val::Number(*number),
_ => return format_err!("number indirection"),
_ => return Err("number indirection".to_error()),
})
},
};
@@ -108,10 +110,11 @@ static VALUE_OF: NativeFunction = NativeFunction {
fn format_exponential(number: f64, precision: Option<usize>) -> Val {
if number.is_infinite() {
return if number.is_sign_positive() {
Val::String(Rc::new("Infinity".to_string()))
"Infinity"
} else {
Val::String(Rc::new("-Infinity".to_string()))
};
"-Infinity"
}
.to_val();
}
let exp_format = match precision {
@@ -125,7 +128,7 @@ fn format_exponential(number: f64, precision: Option<usize>) -> Val {
let exponent = match parts.next() {
Some(e) => e,
None => return Val::String(Rc::new(exp_format)),
None => return exp_format.to_val(),
};
let string = if exponent.starts_with('-') {
@@ -134,5 +137,5 @@ fn format_exponential(number: f64, precision: Option<usize>) -> Val {
format!("{}e+{}", mantissa, exponent)
};
Val::String(Rc::new(string))
string.to_val()
}

View File

@@ -4,17 +4,17 @@ use num_bigint::Sign;
use num_traits::ToPrimitive;
use crate::bigint_methods::op_sub_bigint;
use crate::format_err;
use crate::format_val;
use crate::builtins::error_builtin::ToError;
use crate::builtins::type_error_builtin::ToTypeError;
use crate::native_function::NativeFunction;
use crate::native_function::ThisWrapper;
use crate::number_methods::op_sub_number;
use crate::string_methods::op_sub_string;
use crate::vs_value::ToVal;
use crate::vs_value::Val;
use crate::vs_value::ValTrait;
use crate::vs_value::VsType;
use crate::{builtins::range_error_builtin::to_range_error, range_error};
use crate::{builtins::type_error_builtin::to_type_error, type_error};
pub fn op_plus(left: Val, right: Val) -> Result<Val, Val> {
let left_prim = left.to_primitive();
@@ -24,21 +24,19 @@ pub fn op_plus(left: Val, right: Val) -> Result<Val, Val> {
let right_type = right_prim.typeof_();
if left_type == VsType::String || right_type == VsType::String {
return Ok(Val::String(Rc::new(
left_prim.val_to_string() + &right_prim.val_to_string(),
)));
return Ok((left_prim.val_to_string() + &right_prim.val_to_string()).to_val());
}
if left_type == VsType::BigInt || right_type == VsType::BigInt {
if left_type != right_type {
return type_error!("Cannot mix BigInt and other types");
return Err("Cannot mix BigInt and other types".to_type_error());
}
match (left_prim.as_bigint_data(), right_prim.as_bigint_data()) {
(Some(left_bigint), Some(right_bigint)) => {
return Ok(Val::BigInt(left_bigint + right_bigint));
}
_ => return format_err!("TODO"),
_ => return Err("TODO".to_error()),
}
}
@@ -55,7 +53,9 @@ pub fn op_unary_plus(input: 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)) => Ok(Val::BigInt(left_bigint - right_bigint)),
(Some(_), None) | (None, Some(_)) => return type_error!("Cannot mix BigInt with other types"),
(Some(_), None) | (None, Some(_)) => {
return Err("Cannot mix BigInt with other types".to_type_error())
}
_ => Ok(Val::Number(left.to_number() - right.to_number())),
}
}
@@ -70,9 +70,7 @@ pub fn op_unary_minus(input: 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)) => Ok(Val::BigInt(left_bigint * right_bigint)),
(Some(_), None) | (None, Some(_)) => {
type_error!("Cannot mix BigInt with other types")
}
(Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()),
_ => Ok(Val::Number(left.to_number() * right.to_number())),
}
}
@@ -80,9 +78,7 @@ pub fn op_mul(left: Val, right: Val) -> Result<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)) => Ok(Val::BigInt(left_bigint / right_bigint)),
(Some(_), None) | (None, Some(_)) => {
type_error!("Cannot mix BigInt with other types")
}
(Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()),
_ => Ok(Val::Number(left.to_number() / right.to_number())),
}
}
@@ -90,9 +86,7 @@ pub fn op_div(left: Val, right: Val) -> Result<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)) => Ok(Val::BigInt(left_bigint % right_bigint)),
(Some(_), None) | (None, Some(_)) => {
type_error!("Cannot mix BigInt with other types")
}
(Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()),
_ => Ok(Val::Number(left.to_number() % right.to_number())),
}
}
@@ -111,9 +105,7 @@ pub fn op_exp(left: Val, right: Val) -> Result<Val, Val> {
Ok(Val::BigInt(left_bigint.pow(exp)))
}
(Some(_), None) | (None, Some(_)) => {
type_error!("Cannot mix BigInt with other types")
}
(Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()),
_ => Ok(Val::Number(left.to_number().powf(right.to_number()))),
}
}
@@ -126,7 +118,7 @@ pub fn op_eq(left: Val, right: Val) -> Result<Val, Val> {
(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,
_ => return format_err!("TODO"),
_ => return Err("TODO".to_error()),
}))
}
@@ -138,7 +130,7 @@ pub fn op_ne(left: Val, right: Val) -> Result<Val, Val> {
(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,
_ => return format_err!("TODO"),
_ => return Err("TODO".to_error()),
}))
}
@@ -154,7 +146,7 @@ pub fn op_triple_eq_impl(left: Val, right: Val) -> Result<bool, Val> {
if left.typeof_() != right.typeof_() {
false
} else {
return format_err!("TODO");
return Err("TODO".to_error());
}
}
})
@@ -194,7 +186,7 @@ pub fn op_less(left: Val, right: Val) -> Result<Val, Val> {
if left.typeof_() == VsType::Undefined || right.typeof_() == VsType::Undefined {
false
} else {
return format_err!("TODO");
return Err("TODO".to_error());
}
}
}))
@@ -208,7 +200,7 @@ pub fn op_less_eq(left: Val, right: Val) -> Result<Val, Val> {
(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,
_ => return format_err!("TODO"),
_ => return Err("TODO".to_type_error()),
}))
}
@@ -220,7 +212,7 @@ pub fn op_greater(left: Val, right: Val) -> Result<Val, Val> {
(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,
_ => return format_err!("TODO"),
_ => return Err("TODO".to_error()),
}))
}
@@ -232,7 +224,7 @@ pub fn op_greater_eq(left: Val, right: Val) -> Result<Val, Val> {
(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,
_ => return format_err!("TODO"),
_ => return Err("TODO".to_type_error()),
}))
}
@@ -271,9 +263,7 @@ pub fn to_u32(x: f64) -> u32 {
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(_)) => {
type_error!("Cannot mix BigInt with other types")
}
(Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()),
_ => {
let res_i32 = to_i32(left.to_number()) & to_i32(right.to_number());
Ok(Val::Number(res_i32 as f64))
@@ -284,9 +274,7 @@ pub fn op_bit_and(left: Val, right: Val) -> Result<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)) => Ok(Val::BigInt(left_bigint | right_bigint)),
(Some(_), None) | (None, Some(_)) => {
type_error!("Cannot mix BigInt with other types")
}
(Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()),
_ => {
let res_i32 = to_i32(left.to_number()) | to_i32(right.to_number());
Ok(Val::Number(res_i32 as f64))
@@ -307,9 +295,7 @@ pub fn op_bit_not(input: 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)) => Ok(Val::BigInt(left_bigint ^ right_bigint)),
(Some(_), None) | (None, Some(_)) => {
type_error!("Cannot mix BigInt with other types")
}
(Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()),
_ => {
let res_i32 = to_i32(left.to_number()) ^ to_i32(right.to_number());
Ok(Val::Number(res_i32 as f64))
@@ -322,9 +308,7 @@ pub fn op_left_shift(left: Val, right: Val) -> Result<Val, Val> {
(Some(left_bigint), Some(right_bigint)) => Ok(Val::BigInt(
left_bigint << right_bigint.to_i64().expect("TODO"),
)),
(Some(_), None) | (None, Some(_)) => {
type_error!("Cannot mix BigInt with other types")
}
(Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()),
_ => {
let res_i32 = to_i32(left.to_number()) << (to_u32(right.to_number()) & 0x1f);
Ok(Val::Number(res_i32 as f64))
@@ -335,12 +319,10 @@ pub fn op_left_shift(left: Val, right: Val) -> Result<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)) => {
let right_i64 = right_bigint.to_i64().ok_or(format_val!("TODO"))?;
let right_i64 = right_bigint.to_i64().ok_or("TODO".to_val())?;
Ok(Val::BigInt(left_bigint >> right_i64))
}
(Some(_), None) | (None, Some(_)) => {
type_error!("Cannot mix BigInt with other types")
}
(Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()),
_ => {
let res_i32 = to_i32(left.to_number()) >> (to_u32(right.to_number()) & 0x1f);
Ok(Val::Number(res_i32 as f64))
@@ -350,12 +332,8 @@ pub fn op_right_shift(left: Val, right: Val) -> Result<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(_)) => {
type_error!("BigInts don't support unsigned right shift")
}
(Some(_), None) | (None, Some(_)) => {
type_error!("Cannot mix BigInt with other types")
}
(Some(_), Some(_)) => Err("BigInts don't support unsigned right shift".to_type_error()),
(Some(_), None) | (None, Some(_)) => Err("Cannot mix BigInt with other types".to_type_error()),
_ => {
let res_u32 = to_u32(left.to_number()) >> (to_u32(right.to_number()) & 0x1f);
Ok(Val::Number(res_u32 as f64))
@@ -366,34 +344,35 @@ pub fn op_right_shift_unsigned(left: Val, right: Val) -> Result<Val, Val> {
pub fn op_typeof(input: Val) -> Val {
use VsType::*;
return Val::String(Rc::new(match input.typeof_() {
Undefined => "undefined".to_string(),
Null => "object".to_string(),
Bool => "boolean".to_string(),
Number => "number".to_string(),
BigInt => "bigint".to_string(),
Symbol => "symbol".to_string(),
String => "string".to_string(),
Array => "object".to_string(),
Object => "object".to_string(),
Function => "function".to_string(),
Class => "function".to_string(),
}));
match input.typeof_() {
Undefined => "undefined",
Null => "object",
Bool => "boolean",
Number => "number",
BigInt => "bigint",
Symbol => "symbol",
String => "string",
Array => "object",
Object => "object",
Function => "function",
Class => "function",
}
.to_val()
}
pub fn op_instance_of(_left: Val, _right: Val) -> Result<Val, Val> {
format_err!("TODO: op_instance_of")
Err("TODO: op_instance_of".to_error())
}
pub fn op_in(_left: Val, _right: Val) -> Result<Val, Val> {
format_err!("TODO: op_in")
Err("TODO: op_in".to_error())
}
pub fn op_sub(left: Val, right: Val) -> Result<Val, Val> {
return match left {
Val::Void => format_err!("Internal: Shouldn't happen"), // TODO: Internal errors
Val::Undefined => type_error!("Cannot subscript undefined"),
Val::Null => type_error!("Cannot subscript null"),
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.val_to_string().as_str() {
"toString" => Val::Static(&BOOL_TO_STRING),
"valueOf" => Val::Static(&BOOL_VALUE_OF),
@@ -437,18 +416,18 @@ pub fn op_sub(left: Val, right: Val) -> Result<Val, Val> {
pub fn op_submov(target: &mut Val, subscript: Val, value: Val) -> Result<(), Val> {
match target {
Val::Void => format_err!("Internal: Shouldn't happen"), // TODO: Internal errors
Val::Undefined => type_error!("Cannot assign to subscript of undefined"),
Val::Null => type_error!("Cannot assign to subscript of null"),
Val::Bool(_) => type_error!("Cannot assign to subscript of bool"),
Val::Number(_) => type_error!("Cannot assign to subscript of number"),
Val::BigInt(_) => type_error!("Cannot assign to subscript of bigint"),
Val::Symbol(_) => type_error!("Cannot assign to subscript of symbol"),
Val::String(_) => type_error!("Cannot assign to subscript of string"),
Val::Void => Err("Internal: Shouldn't happen".to_error()), // TODO: Internal errors
Val::Undefined => Err("Cannot assign to subscript of undefined".to_type_error()),
Val::Null => Err("Cannot assign to subscript of null".to_type_error()),
Val::Bool(_) => Err("Cannot assign to subscript of bool".to_type_error()),
Val::Number(_) => Err("Cannot assign to subscript of number".to_type_error()),
Val::BigInt(_) => Err("Cannot assign to subscript of bigint".to_type_error()),
Val::Symbol(_) => Err("Cannot assign to subscript of symbol".to_type_error()),
Val::String(_) => Err("Cannot assign to subscript of string".to_type_error()),
Val::Array(array_data) => {
let subscript_index = match subscript.to_index() {
// TODO: Internal errors
None => return format_err!("TODO: non-uint array subscript assignment"),
None => return Err("TODO: non-uint array subscript assignment".to_type_error()),
Some(i) => i,
};
@@ -458,7 +437,7 @@ pub fn op_submov(target: &mut Val, subscript: Val, value: Val) -> Result<(), Val
array_data_mut.elements[subscript_index] = value;
} else {
if subscript_index - array_data_mut.elements.len() > 100 {
return format_err!("TODO: Sparse arrays");
return Err("TODO: Sparse arrays".to_type_error());
}
while subscript_index > array_data_mut.elements.len() {
@@ -483,18 +462,18 @@ pub fn op_submov(target: &mut Val, subscript: Val, value: Val) -> Result<(), Val
Ok(())
}
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"),
Val::Function(_) => Err("TODO: function subscript assignment".to_type_error()),
Val::Class(_) => Err("Cannot assign to subscript of class".to_type_error()),
Val::Static(_) => Err("Cannot assign to subscript of static value".to_type_error()),
Val::Custom(_) => Err("TODO: Assign to subscript of custom value".to_type_error()),
}
}
static BOOL_TO_STRING: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
Val::Bool(b) => Val::String(Rc::new(b.to_string())),
_ => return format_err!("bool indirection"),
Val::Bool(b) => b.to_string().to_val(),
_ => return Err("bool indirection".to_type_error()),
})
},
};
@@ -503,7 +482,7 @@ static BOOL_VALUE_OF: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
Val::Bool(b) => Val::Bool(*b),
_ => return format_err!("bool indirection"),
_ => return Err("bool indirection".to_type_error()),
})
},
};

View File

@@ -1,11 +1,10 @@
use std::{rc::Rc, str::Chars};
use crate::{
format_err,
builtins::error_builtin::ToError,
helpers::{to_wrapping_index, to_wrapping_index_clamped},
native_function::{NativeFunction, ThisWrapper},
vs_array::VsArray,
vs_value::Val,
vs_value::{ToVal, Val},
ValTrait,
};
@@ -30,8 +29,8 @@ pub fn op_sub_string(string_data: &Rc<String>, subscript: &Val) -> Val {
}
match unicode_at(string_bytes, string_bytes.len(), right_index) {
Some(char) => Val::String(Rc::new(char.to_string())),
None => Val::String(Rc::new(String::from(""))),
Some(char) => char.to_string().to_val(),
None => "".to_val(),
}
}
@@ -96,11 +95,11 @@ static AT: NativeFunction = NativeFunction {
};
match unicode_at(string_bytes, string_bytes.len(), index) {
Some(char) => Val::String(Rc::new(char.to_string())),
None => Val::String(Rc::new(String::from(""))),
Some(char) => char.to_string().to_val(),
None => "".to_val(),
}
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -124,7 +123,7 @@ static CODE_POINT_AT: NativeFunction = NativeFunction {
None => Val::Undefined,
}
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -139,9 +138,9 @@ static CONCAT: NativeFunction = NativeFunction {
result.push_str(param.val_to_string().as_str());
}
Val::String(Rc::new(result))
result.to_val()
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -184,7 +183,7 @@ static ENDS_WITH: NativeFunction = NativeFunction {
Val::Bool(true)
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -216,7 +215,7 @@ static INCLUDES: NativeFunction = NativeFunction {
None => Val::Bool(false),
}
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -248,7 +247,7 @@ static INDEX_OF: NativeFunction = NativeFunction {
None => Val::Number(-1.0),
}
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -280,7 +279,7 @@ static LAST_INDEX_OF: NativeFunction = NativeFunction {
None => Val::Number(-1.0),
}
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -290,9 +289,9 @@ static TODO_LOCALE: NativeFunction = NativeFunction {
// TODO: Ok(...)
match this.get() {
Val::String(_string_data) => {
return format_err!("TODO: locale");
return Err("TODO: locale".to_error());
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
}
},
};
@@ -302,9 +301,9 @@ static TODO_REGEXES: NativeFunction = NativeFunction {
// TODO: Ok(...)
match this.get() {
Val::String(_string_data) => {
return format_err!("TODO: regexes");
return Err("TODO: regexes".to_error());
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
}
},
};
@@ -315,9 +314,9 @@ static NORMALIZE: NativeFunction = NativeFunction {
match this.get() {
Val::String(_string_data) => {
// Consider https://docs.rs/unicode-normalization/latest/unicode_normalization/
return format_err!("TODO: normalize");
return Err("TODO: normalize".to_error());
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
}
},
};
@@ -369,9 +368,9 @@ static PAD_END: NativeFunction = NativeFunction {
}
}
Val::String(Rc::new(string))
string.to_val()
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -425,9 +424,9 @@ static PAD_START: NativeFunction = NativeFunction {
prefix.push_str(string_data);
Val::String(Rc::new(prefix))
prefix.to_val()
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -450,9 +449,9 @@ static REPEAT: NativeFunction = NativeFunction {
result.push_str(string_data);
}
Val::String(Rc::new(result))
result.to_val()
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -484,9 +483,9 @@ static SLICE: NativeFunction = NativeFunction {
}
}
Val::String(Rc::new(new_string))
new_string.to_val()
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -512,19 +511,19 @@ static SPLIT: NativeFunction = NativeFunction {
let mut result = Vec::<Val>::new();
if limit == 0 {
return Ok(Val::Array(Rc::new(VsArray::from(result))));
return Ok(result.to_val());
}
if separator.is_empty() {
for c in string_data.chars() {
result.push(Val::String(Rc::new(c.to_string())));
result.push(c.to_val());
if result.len() == limit {
break;
}
}
return Ok(Val::Array(Rc::new(VsArray::from(result))));
return Ok(result.to_val());
}
let mut part = String::new();
@@ -534,7 +533,7 @@ static SPLIT: NativeFunction = NativeFunction {
if match_chars(&mut str_chars, &separator) {
let mut new_part = String::new();
std::mem::swap(&mut new_part, &mut part);
result.push(Val::String(Rc::new(new_part)));
result.push(new_part.to_val());
if result.len() == limit {
break;
@@ -543,16 +542,16 @@ static SPLIT: NativeFunction = NativeFunction {
match str_chars.next() {
Some(c) => part.push(c),
None => {
result.push(Val::String(Rc::new(part)));
result.push(part.to_val());
break;
}
}
}
}
Val::Array(Rc::new(VsArray::from(result)))
result.to_val()
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -593,7 +592,7 @@ static STARTS_WITH: NativeFunction = NativeFunction {
Val::Bool(true)
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -634,9 +633,9 @@ static SUBSTRING: NativeFunction = NativeFunction {
}
}
Val::String(Rc::new(new_string))
new_string.to_val()
}
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -644,11 +643,8 @@ static SUBSTRING: NativeFunction = NativeFunction {
static TO_LOWER_CASE: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
Val::String(string_data) => {
let lowercased_string = string_data.to_lowercase();
Val::String(Rc::new(lowercased_string))
}
_ => return format_err!("string indirection"),
Val::String(string_data) => string_data.to_lowercase().to_val(),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -657,7 +653,7 @@ static TO_STRING: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
Val::String(string_data) => Val::String(string_data.clone()),
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -665,11 +661,8 @@ static TO_STRING: NativeFunction = NativeFunction {
static TO_UPPER_CASE: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
Val::String(string_data) => {
let uppercased_string = string_data.to_uppercase();
Val::String(Rc::new(uppercased_string))
}
_ => return format_err!("string indirection"),
Val::String(string_data) => string_data.to_uppercase().to_val(),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -677,11 +670,8 @@ static TO_UPPER_CASE: NativeFunction = NativeFunction {
static TRIM: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
Val::String(string_data) => {
let trimmed_string = string_data.trim();
Val::String(Rc::new(trimmed_string.to_owned()))
}
_ => return format_err!("string indirection"),
Val::String(string_data) => string_data.trim().to_val(),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -689,11 +679,8 @@ static TRIM: NativeFunction = NativeFunction {
static TRIM_END: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
Val::String(string_data) => {
let trimmed_string = string_data.trim_end();
Val::String(Rc::new(trimmed_string.to_owned()))
}
_ => return format_err!("string indirection"),
Val::String(string_data) => string_data.trim_end().to_val(),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -701,11 +688,8 @@ static TRIM_END: NativeFunction = NativeFunction {
static TRIM_START: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
Val::String(string_data) => {
let trimmed_string = string_data.trim_start();
Val::String(Rc::new(trimmed_string.to_owned()))
}
_ => return format_err!("string indirection"),
Val::String(string_data) => string_data.trim_start().to_val(),
_ => return Err("string indirection".to_error()),
})
},
};
@@ -714,7 +698,7 @@ static VALUE_OF: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
Val::String(string_data) => Val::String(string_data.clone()),
_ => return format_err!("string indirection"),
_ => return Err("string indirection".to_error()),
})
},
};

View File

@@ -1,16 +1,9 @@
use std::rc::Rc;
use crate::{
format_err,
builtins::error_builtin::ToError,
native_function::{NativeFunction, ThisWrapper},
vs_value::Val,
};
pub static TODO: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
match this.get() {
Val::Number(_number) => return format_err!("TODO: locale"),
_ => return format_err!("number indirection"),
}
},
fn_: |_: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> { Err("TODO".to_error()) },
};

View File

@@ -1,10 +1,8 @@
use std::rc::Rc;
use crate::builtins::error_builtin::to_error;
use crate::builtins::error_builtin::ToError;
use crate::bytecode_decoder::BytecodeDecoder;
use crate::error;
use crate::first_stack_frame::FirstStackFrame;
use crate::native_function::ThisWrapper;
use crate::stack_frame::FrameStepOk;
use crate::stack_frame::StackFrame;
use crate::vs_value::{LoadFunctionResult, Val, ValTrait};
@@ -52,7 +50,7 @@ impl VirtualMachine {
}
}
error!("step limit reached")
Err("step limit reached".to_error())
}
None => {
while self.stack.len() > 0 {

View File

@@ -8,14 +8,15 @@ use crate::array_higher_functions::{
array_flat_map::FLAT_MAP, array_map::MAP, array_reduce::REDUCE, array_reduce_right::REDUCE_RIGHT,
array_some::SOME, array_sort::SORT,
};
use crate::format_err;
use crate::builtins::error_builtin::ToError;
use crate::builtins::type_error_builtin::ToTypeError;
use crate::helpers::{to_wrapping_index, to_wrapping_index_clamped};
use crate::native_function::{NativeFunction, ThisWrapper};
use crate::operations::op_triple_eq_impl;
use crate::todo_fn::TODO;
use crate::vs_class::VsClass;
use crate::vs_object::VsObject;
use crate::vs_value::{LoadFunctionResult, Val, ValTrait, VsType};
use crate::{builtins::type_error_builtin::to_type_error, type_error};
use crate::vs_value::{LoadFunctionResult, ToVal, ToValString, Val, ValTrait, VsType};
#[derive(Clone, Debug)]
pub struct VsArray {
@@ -47,6 +48,12 @@ impl VsArray {
}
}
impl ToVal for VsArray {
fn to_val(self) -> Val {
Val::Array(Rc::new(self))
}
}
pub struct ArrayPrototype {}
static ARRAY_PROTOTYPE: ArrayPrototype = ArrayPrototype {};
@@ -68,7 +75,7 @@ impl ValTrait for ArrayPrototype {
false
}
fn to_primitive(&self) -> Val {
Val::String(Rc::new("".to_string()))
self.to_val_string()
}
fn is_truthy(&self) -> bool {
true
@@ -116,7 +123,7 @@ impl ValTrait for ArrayPrototype {
"includes" => &INCLUDES,
"indexOf" => &INDEX_OF,
"join" => &JOIN,
"keys" => &KEYS,
"keys" => &TODO,
"lastIndexOf" => &LAST_INDEX_OF,
"map" => &MAP,
"pop" => &POP,
@@ -129,16 +136,16 @@ impl ValTrait for ArrayPrototype {
"some" => &SOME,
"sort" => &SORT,
"splice" => &SPLICE,
"toLocaleString" => &TO_LOCALE_STRING,
"toLocaleString" => &TODO,
"toString" => &TO_STRING,
"unshift" => &UNSHIFT,
"values" => &VALUES,
"values" => &TODO,
_ => return Ok(Val::Undefined),
}))
}
fn submov(&mut self, _key: Val, _value: Val) -> Result<(), Val> {
type_error!("Cannot assign to subscript of Array.prototype")
Err("Cannot assign to subscript of Array.prototype".to_type_error())
}
fn next(&mut self) -> LoadFunctionResult {
@@ -161,7 +168,7 @@ static AT: NativeFunction = NativeFunction {
None => Val::Undefined,
Some(i) => array_data.elements[i].clone(),
},
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -185,9 +192,9 @@ static CONCAT: NativeFunction = NativeFunction {
}
}
Val::Array(Rc::new(new_array))
new_array.to_val()
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -202,7 +209,7 @@ static COPY_WITHIN: NativeFunction = NativeFunction {
let ulen = array_data_mut.elements.len();
if ulen > isize::MAX as usize {
return format_err!("TODO: array len exceeds isize");
return Err("TODO: array len exceeds isize".to_error());
}
let mut target = match params.get(0) {
@@ -261,7 +268,7 @@ static COPY_WITHIN: NativeFunction = NativeFunction {
this.clone()
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -269,8 +276,8 @@ static COPY_WITHIN: NativeFunction = NativeFunction {
static ENTRIES: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
match this.get() {
Val::Array(_array_data) => return format_err!("TODO: iterators"),
_ => return format_err!("array indirection"),
Val::Array(_array_data) => return Err("TODO: iterators".to_error()),
_ => return Err("array indirection".to_error()),
};
},
};
@@ -302,7 +309,7 @@ static FILL: NativeFunction = NativeFunction {
this.clone()
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -312,7 +319,7 @@ static FLAT: NativeFunction = NativeFunction {
Ok(match this.get() {
Val::Array(array_data) => {
if params.len() > 0 {
return format_err!("TODO: .flat depth parameter");
return Err("TODO: .flat depth parameter".to_error());
}
let mut new_elems = Vec::<Val>::new();
@@ -330,9 +337,9 @@ static FLAT: NativeFunction = NativeFunction {
}
}
Val::Array(Rc::new(VsArray::from(new_elems)))
new_elems.to_val()
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -355,7 +362,7 @@ static INCLUDES: NativeFunction = NativeFunction {
Val::Bool(false)
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -378,7 +385,7 @@ static INDEX_OF: NativeFunction = NativeFunction {
Val::Number(-1.0)
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -388,11 +395,11 @@ static JOIN: NativeFunction = NativeFunction {
Ok(match this.get() {
Val::Array(vals) => {
if vals.elements.len() == 0 {
return Ok(Val::String(Rc::new("".to_string())));
return Ok("".to_val());
}
if vals.elements.len() == 1 {
return Ok(Val::String(Rc::new(vals.elements[0].val_to_string())));
return Ok(vals.elements[0].to_val_string());
}
let separator = params.get(0).unwrap_or(&Val::Undefined);
@@ -416,25 +423,13 @@ static JOIN: NativeFunction = NativeFunction {
};
}
Val::String(Rc::new(res))
res.to_val()
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
static KEYS: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
// TODO: Ok(...)
match this.get() {
Val::Array(_array_data) => {
return format_err!("TODO: KEYS");
}
_ => return format_err!("array indirection"),
};
},
};
static LAST_INDEX_OF: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, params: Vec<Val>| -> Result<Val, Val> {
Ok(match this.get() {
@@ -453,7 +448,7 @@ static LAST_INDEX_OF: NativeFunction = NativeFunction {
Val::Number(-1_f64)
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -479,7 +474,7 @@ static POP: NativeFunction = NativeFunction {
_ => removed_el,
}
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -498,7 +493,7 @@ static PUSH: NativeFunction = NativeFunction {
Val::Number(array_data_mut.elements.len() as f64)
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -527,7 +522,7 @@ static REVERSE: NativeFunction = NativeFunction {
this.clone()
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -546,7 +541,7 @@ static SHIFT: NativeFunction = NativeFunction {
array_data_mut.elements.remove(0)
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -571,9 +566,9 @@ static SLICE: NativeFunction = NativeFunction {
new_elems.push(array_data.elements[i as usize].clone());
}
Val::Array(Rc::new(VsArray::from(new_elems)))
new_elems.to_val()
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
@@ -650,29 +645,17 @@ static SPLICE: NativeFunction = NativeFunction {
}
}
Val::Array(Rc::new(VsArray::from(deleted_elements)))
deleted_elements.to_val()
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
static TO_LOCALE_STRING: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
// TODO: Ok(...)
match this.get() {
Val::Array(_array_data) => {
return format_err!("TODO: TO_LOCALE_STRING");
}
_ => return format_err!("array indirection"),
};
},
};
// TODO: Share this? (JS doesn't?)
static TO_STRING: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
Ok(Val::String(Rc::new(this.get().val_to_string())))
Ok(this.get().to_val_string())
},
};
@@ -693,19 +676,7 @@ static UNSHIFT: NativeFunction = NativeFunction {
Val::Number(array_data_mut.elements.len() as f64)
}
_ => return format_err!("array indirection"),
_ => return Err("array indirection".to_error()),
})
},
};
static VALUES: NativeFunction = NativeFunction {
fn_: |this: ThisWrapper, _params: Vec<Val>| -> Result<Val, Val> {
// TODO: Ok(...)
match this.get() {
Val::Array(_array_data) => {
return format_err!("TODO: VALUES");
}
_ => return format_err!("array indirection"),
};
},
};

View File

@@ -1,3 +1,7 @@
use std::rc::Rc;
use crate::vs_value::ToVal;
use super::vs_value::Val;
#[derive(Debug)]
@@ -7,3 +11,9 @@ pub struct VsClass {
}
impl VsClass {}
impl ToVal for VsClass {
fn to_val(self) -> Val {
Val::Class(Rc::new(self))
}
}

View File

@@ -1,5 +1,7 @@
use std::rc::Rc;
use crate::vs_value::ToVal;
use super::bytecode_decoder::BytecodeDecoder;
use super::bytecode_stack_frame::BytecodeStackFrame;
use super::stack_frame::StackFrame;
@@ -60,3 +62,9 @@ impl VsFunction {
});
}
}
impl ToVal for VsFunction {
fn to_val(self) -> Val {
Val::Function(Rc::new(self))
}
}

View File

@@ -1,6 +1,8 @@
use std::collections::BTreeMap;
use std::rc::Rc;
use crate::vs_symbol::VsSymbol;
use crate::vs_value::ToVal;
use super::operations::op_sub;
use super::vs_value::{Val, ValTrait};
@@ -32,3 +34,9 @@ impl VsObject {
}
}
}
impl ToVal for VsObject {
fn to_val(self) -> Val {
Val::Object(Rc::new(self))
}
}

View File

@@ -3,7 +3,8 @@ use std::rc::Rc;
use num_bigint::BigInt;
use crate::format_err;
use crate::builtins::error_builtin::ToError;
use crate::vs_value::ToVal;
use super::bytecode_decoder::{BytecodeDecoder, BytecodeType};
use super::vs_array::VsArray;
@@ -18,12 +19,12 @@ pub struct VsPointer {
}
impl VsPointer {
pub fn new(bytecode: &Rc<Vec<u8>>, pos: usize) -> Val {
return Val::Custom(Rc::new(VsPointer {
pub fn new(bytecode: &Rc<Vec<u8>>, pos: usize) -> VsPointer {
VsPointer {
bytecode: bytecode.clone(),
pos,
resolved: RefCell::new(None),
}));
}
}
fn resolve(&self) -> Val {
@@ -146,7 +147,7 @@ impl ValTrait for VsPointer {
}
fn submov(&mut self, _subscript: Val, _value: Val) -> Result<(), Val> {
format_err!("TODO: Probably an exception, but might be possible")
Err("TODO: Probably an exception, but might be possible".to_error())
}
fn next(&mut self) -> LoadFunctionResult {
@@ -161,3 +162,9 @@ impl ValTrait for VsPointer {
self.resolve().codify()
}
}
impl ToVal for VsPointer {
fn to_val(self) -> Val {
Val::Custom(Rc::new(self))
}
}

View File

@@ -6,8 +6,7 @@ use num_bigint::BigInt;
use num_traits::cast::ToPrimitive;
use num_traits::Zero;
use crate::format_val;
use crate::native_function::ThisWrapper;
use crate::native_function::{NativeFunction, ThisWrapper};
use crate::operations::{op_sub, op_submov};
use crate::stack_frame::StackFrame;
use crate::vs_array::VsArray;
@@ -55,6 +54,37 @@ pub enum LoadFunctionResult {
NativeFunction(fn(this: ThisWrapper, params: Vec<Val>) -> Result<Val, Val>),
}
pub trait ToLoadFunctionResult {
fn to_load_function_result(self) -> LoadFunctionResult;
}
impl ToLoadFunctionResult for StackFrame {
fn to_load_function_result(self) -> LoadFunctionResult {
LoadFunctionResult::StackFrame(self)
}
}
impl ToLoadFunctionResult for fn(this: ThisWrapper, params: Vec<Val>) -> Result<Val, Val> {
fn to_load_function_result(self) -> LoadFunctionResult {
LoadFunctionResult::NativeFunction(self)
}
}
impl ToLoadFunctionResult for NativeFunction {
fn to_load_function_result(self) -> LoadFunctionResult {
self.fn_.to_load_function_result()
}
}
impl<T> From<T> for LoadFunctionResult
where
T: ToLoadFunctionResult,
{
fn from(value: T) -> Self {
value.to_load_function_result()
}
}
pub trait ValTrait {
fn typeof_(&self) -> VsType;
fn val_to_string(&self) -> String;
@@ -238,10 +268,10 @@ impl ValTrait for Val {
fn to_primitive(&self) -> Val {
if self.is_primitive() {
return self.clone();
self.clone()
} else {
self.to_val_string()
}
return Val::String(Rc::new(self.val_to_string()));
}
fn is_truthy(&self) -> bool {
@@ -290,7 +320,7 @@ impl ValTrait for Val {
use Val::*;
return match self {
Function(f) => Some(Val::Function(Rc::new(f.bind(params)))),
Function(f) => Some(f.bind(params).to_val()),
Custom(val) => val.bind(params),
_ => None,
@@ -368,7 +398,7 @@ impl ValTrait for Val {
match self {
// TODO: iterator
_ => {
let next_fn = op_sub(self.clone(), Val::String(Rc::new("next".into())));
let next_fn = op_sub(self.clone(), "next".to_val());
match next_fn {
Ok(next_fn) => next_fn.load_function(),
@@ -416,7 +446,7 @@ impl ValTrait for Val {
let mut res = String::new();
if let Some(proto) = &object.prototype {
match op_sub(proto.clone(), format_val!("name")) {
match op_sub(proto.clone(), "name".to_val()) {
Ok(name) => {
if name.typeof_() == VsType::String {
res += format!("{}", name.val_to_string()).as_str();
@@ -459,6 +489,71 @@ impl ValTrait for Val {
}
}
pub trait ToValString {
fn to_val_string(&self) -> Val;
}
impl<T: ValTrait> ToValString for T {
fn to_val_string(&self) -> Val {
Val::String(Rc::new(self.val_to_string()))
}
}
pub trait ToVal {
fn to_val(self) -> Val;
}
impl<T> From<T> for Val
where
T: ToVal,
{
fn from(value: T) -> Val {
value.to_val()
}
}
impl ToVal for char {
fn to_val(self) -> Val {
self.to_string().to_val()
}
}
impl ToVal for &str {
fn to_val(self) -> Val {
Val::String(Rc::new(self.to_string()))
}
}
impl ToVal for String {
fn to_val(self) -> Val {
Val::String(Rc::new(self))
}
}
impl ToVal for f64 {
fn to_val(self) -> Val {
Val::Number(self)
}
}
impl ToVal for bool {
fn to_val(self) -> Val {
Val::Bool(self)
}
}
impl ToVal for BigInt {
fn to_val(self) -> Val {
Val::BigInt(self)
}
}
impl ToVal for Vec<Val> {
fn to_val(self) -> Val {
Val::Array(Rc::new(VsArray::from(self)))
}
}
impl std::fmt::Display for Val {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
@@ -493,7 +588,7 @@ impl std::fmt::Display for Val {
}
Val::Object(object) => {
if let Some(proto) = &object.prototype {
match op_sub(proto.clone(), format_val!("name")) {
match op_sub(proto.clone(), "name".to_val()) {
Ok(name) => {
if name.typeof_() == VsType::String {
write!(f, "{} ", name.val_to_string())?;