From 706fb784427b5c422cd31edadd94d44ed871e9de Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Thu, 25 May 2023 13:15:15 +1000 Subject: [PATCH] Add symbols --- valuescript_vm/src/builtins/array_builtin.rs | 4 ++- valuescript_vm/src/builtins/error_builtin.rs | 2 ++ .../src/builtins/range_error_builtin.rs | 2 ++ .../src/builtins/type_error_builtin.rs | 2 ++ valuescript_vm/src/bytecode_decoder.rs | 1 + valuescript_vm/src/bytecode_stack_frame.rs | 1 + valuescript_vm/src/lib.rs | 1 + valuescript_vm/src/operations.rs | 16 +++++++----- valuescript_vm/src/vs_array.rs | 2 ++ valuescript_vm/src/vs_object.rs | 26 +++++++++++++------ valuescript_vm/src/vs_pointer.rs | 1 + valuescript_vm/src/vs_symbol.rs | 10 +++++++ valuescript_vm/src/vs_value.rs | 12 +++++++++ 13 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 valuescript_vm/src/vs_symbol.rs diff --git a/valuescript_vm/src/builtins/array_builtin.rs b/valuescript_vm/src/builtins/array_builtin.rs index 330c058..3b52e46 100644 --- a/valuescript_vm/src/builtins/array_builtin.rs +++ b/valuescript_vm/src/builtins/array_builtin.rs @@ -118,7 +118,9 @@ static FROM: NativeFunction = NativeFunction { .collect(), ))), Val::Void | Val::Undefined | Val::Null => return type_error!("items is not iterable"), - Val::Bool(..) | Val::Number(..) | Val::BigInt(..) => Val::Array(Rc::new(VsArray::new())), + Val::Bool(..) | Val::Number(..) | Val::BigInt(..) | Val::Symbol(..) => { + Val::Array(Rc::new(VsArray::new())) + } Val::Object(..) | Val::Function(..) | Val::Class(..) | Val::Static(..) | Val::Custom(..) => { let len = op_sub( first_param.clone(), diff --git a/valuescript_vm/src/builtins/error_builtin.rs b/valuescript_vm/src/builtins/error_builtin.rs index 1a5daf0..c2948b1 100644 --- a/valuescript_vm/src/builtins/error_builtin.rs +++ b/valuescript_vm/src/builtins/error_builtin.rs @@ -104,6 +104,7 @@ pub fn to_error(_: ThisWrapper, params: Vec) -> Result { None => "".to_string(), })), )]), + symbol_map: Default::default(), prototype: Some(make_error_prototype()), }))) } @@ -118,6 +119,7 @@ fn make_error_prototype() -> Val { ), ("toString".to_string(), Val::Static(&ERROR_TO_STRING)), ]), + symbol_map: Default::default(), prototype: None, })) } diff --git a/valuescript_vm/src/builtins/range_error_builtin.rs b/valuescript_vm/src/builtins/range_error_builtin.rs index 2ddfb0a..719d965 100644 --- a/valuescript_vm/src/builtins/range_error_builtin.rs +++ b/valuescript_vm/src/builtins/range_error_builtin.rs @@ -95,6 +95,7 @@ pub fn to_range_error(_: ThisWrapper, params: Vec) -> Result { None => "".to_string(), })), )]), + symbol_map: Default::default(), prototype: Some(make_range_error_prototype()), }))) } @@ -109,6 +110,7 @@ fn make_range_error_prototype() -> Val { ), ("toString".to_string(), Val::Static(&RANGE_ERROR_TO_STRING)), ]), + symbol_map: Default::default(), prototype: None, })) } diff --git a/valuescript_vm/src/builtins/type_error_builtin.rs b/valuescript_vm/src/builtins/type_error_builtin.rs index 77e2b47..f42275f 100644 --- a/valuescript_vm/src/builtins/type_error_builtin.rs +++ b/valuescript_vm/src/builtins/type_error_builtin.rs @@ -95,6 +95,7 @@ pub fn to_type_error(_: ThisWrapper, params: Vec) -> Result { None => "".to_string(), })), )]), + symbol_map: Default::default(), prototype: Some(make_type_error_prototype()), }))) } @@ -109,6 +110,7 @@ fn make_type_error_prototype() -> Val { ), ("toString".to_string(), Val::Static(&TYPE_ERROR_TO_STRING)), ]), + symbol_map: Default::default(), prototype: None, })) } diff --git a/valuescript_vm/src/bytecode_decoder.rs b/valuescript_vm/src/bytecode_decoder.rs index 3dee123..dc208cc 100644 --- a/valuescript_vm/src/bytecode_decoder.rs +++ b/valuescript_vm/src/bytecode_decoder.rs @@ -127,6 +127,7 @@ impl BytecodeDecoder { Val::Object(Rc::new(VsObject { string_map: obj, + symbol_map: Default::default(), prototype: None, })) } diff --git a/valuescript_vm/src/bytecode_stack_frame.rs b/valuescript_vm/src/bytecode_stack_frame.rs index 35a2edd..af3d98e 100644 --- a/valuescript_vm/src/bytecode_stack_frame.rs +++ b/valuescript_vm/src/bytecode_stack_frame.rs @@ -377,6 +377,7 @@ impl StackFrameTrait for BytecodeStackFrame { let mut instance = Val::Object(Rc::new(VsObject { string_map: Default::default(), + symbol_map: Default::default(), prototype: Some(class.instance_prototype.clone()), })); diff --git a/valuescript_vm/src/lib.rs b/valuescript_vm/src/lib.rs index dbadd27..e7ee94f 100644 --- a/valuescript_vm/src/lib.rs +++ b/valuescript_vm/src/lib.rs @@ -19,6 +19,7 @@ mod vs_class; mod vs_function; pub mod vs_object; mod vs_pointer; +mod vs_symbol; pub mod vs_value; pub use virtual_machine::VirtualMachine; diff --git a/valuescript_vm/src/operations.rs b/valuescript_vm/src/operations.rs index 9818d06..f6e790d 100644 --- a/valuescript_vm/src/operations.rs +++ b/valuescript_vm/src/operations.rs @@ -372,6 +372,7 @@ pub fn op_typeof(input: Val) -> Val { 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(), @@ -400,6 +401,7 @@ pub fn op_sub(left: Val, right: Val) -> Result { }), 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)), Val::Array(array_data) => { let right_index = match right.to_index() { @@ -436,14 +438,16 @@ pub fn op_sub(left: Val, right: Val) -> Result { 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 => format_err!("Cannot assign to subscript of undefined"), - Val::Null => format_err!("Cannot assign to subscript of null"), - Val::Bool(_) => format_err!("Cannot assign to subscript of bool"), - Val::Number(_) => format_err!("Cannot assign to subscript of number"), - Val::BigInt(_) => format_err!("Cannot assign to subscript of bigint"), - Val::String(_) => format_err!("Cannot assign to subscript of string"), + Val::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::Array(array_data) => { let subscript_index = match subscript.to_index() { + // TODO: Internal errors None => return format_err!("TODO: non-uint array subscript assignment"), Some(i) => i, }; diff --git a/valuescript_vm/src/vs_array.rs b/valuescript_vm/src/vs_array.rs index 762b417..4956d7b 100644 --- a/valuescript_vm/src/vs_array.rs +++ b/valuescript_vm/src/vs_array.rs @@ -29,6 +29,7 @@ impl VsArray { elements: vals, object: VsObject { string_map: Default::default(), + symbol_map: Default::default(), prototype: Some(Val::Static(&ARRAY_PROTOTYPE)), }, }; @@ -39,6 +40,7 @@ impl VsArray { elements: vec![], object: VsObject { string_map: Default::default(), + symbol_map: Default::default(), prototype: Some(Val::Static(&ARRAY_PROTOTYPE)), }, }; diff --git a/valuescript_vm/src/vs_object.rs b/valuescript_vm/src/vs_object.rs index 76611eb..45a5c96 100644 --- a/valuescript_vm/src/vs_object.rs +++ b/valuescript_vm/src/vs_object.rs @@ -1,24 +1,34 @@ use std::collections::BTreeMap; +use crate::vs_symbol::VsSymbol; + use super::operations::op_sub; use super::vs_value::{Val, ValTrait}; #[derive(Clone, Default, Debug)] pub struct VsObject { pub string_map: BTreeMap, + pub symbol_map: BTreeMap, pub prototype: Option, } impl VsObject { pub fn sub(&self, key: Val) -> Val { - return match self.string_map.get(&key.val_to_string()) { - Some(val) => val.clone(), - None => match &self.prototype { - Some(prototype) => op_sub(prototype.clone(), key) - .map_err(|e| e.val_to_string()) - .unwrap(), // TODO: Exception - None => Val::Undefined, - }, + let val = match &key { + Val::String(string) => self.string_map.get(&**string), + Val::Symbol(symbol) => self.symbol_map.get(symbol), + _ => self.string_map.get(&key.val_to_string()), }; + + if let Some(val) = val { + return val.clone(); + } + + match &self.prototype { + Some(prototype) => op_sub(prototype.clone(), key) + .map_err(|e| e.val_to_string()) + .unwrap(), // TODO: Exception + None => Val::Undefined, + } } } diff --git a/valuescript_vm/src/vs_pointer.rs b/valuescript_vm/src/vs_pointer.rs index 436ea66..af409b0 100644 --- a/valuescript_vm/src/vs_pointer.rs +++ b/valuescript_vm/src/vs_pointer.rs @@ -96,6 +96,7 @@ impl ValTrait for VsPointer { VsType::Bool => true, VsType::Number => true, VsType::BigInt => true, + VsType::Symbol => true, VsType::String => true, VsType::Array => false, VsType::Object => false, diff --git a/valuescript_vm/src/vs_symbol.rs b/valuescript_vm/src/vs_symbol.rs new file mode 100644 index 0000000..fc29b5f --- /dev/null +++ b/valuescript_vm/src/vs_symbol.rs @@ -0,0 +1,10 @@ +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum VsSymbol { + ITERATOR, +} + +pub fn symbol_to_name(symbol: VsSymbol) -> &'static str { + match symbol { + VsSymbol::ITERATOR => "iterator", + } +} diff --git a/valuescript_vm/src/vs_value.rs b/valuescript_vm/src/vs_value.rs index a2616a1..7736c50 100644 --- a/valuescript_vm/src/vs_value.rs +++ b/valuescript_vm/src/vs_value.rs @@ -14,6 +14,7 @@ use crate::vs_array::VsArray; use crate::vs_class::VsClass; use crate::vs_function::VsFunction; use crate::vs_object::VsObject; +use crate::vs_symbol::{symbol_to_name, VsSymbol}; #[derive(Clone, Debug)] pub enum Val { @@ -23,6 +24,7 @@ pub enum Val { Bool(bool), Number(f64), BigInt(BigInt), + Symbol(VsSymbol), String(Rc), Array(Rc), Object(Rc), @@ -39,6 +41,7 @@ pub enum VsType { Bool, Number, BigInt, + Symbol, String, Array, Object, @@ -97,6 +100,7 @@ impl ValTrait for Val { Bool(_) => VsType::Bool, Number(_) => VsType::Number, BigInt(_) => VsType::BigInt, + Symbol(_) => VsType::Symbol, String(_) => VsType::String, Array(_) => VsType::Array, Object(_) => VsType::Object, @@ -127,6 +131,7 @@ impl ValTrait for Val { } } // TODO: Match js's number string format BigInt(x) => x.to_string(), + Symbol(s) => format!("Symbol(Symbol.{})", symbol_to_name(s.clone())), String(s) => s.to_string(), Array(vals) => { if vals.elements.len() == 0 { @@ -169,6 +174,7 @@ impl ValTrait for Val { Bool(b) => *b as u8 as f64, Number(x) => *x, BigInt(x) => x.to_f64().unwrap_or(f64::NAN), + Symbol(_) => f64::NAN, // TODO: Should be TypeError String(s) => f64::from_str(s).unwrap_or(f64::NAN), Array(vals) => match vals.elements.len() { 0 => 0_f64, @@ -193,6 +199,7 @@ impl ValTrait for Val { Bool(_) => None, Number(x) => number_to_index(*x), BigInt(b) => number_to_index(b.to_f64().unwrap_or(f64::NAN)), + Symbol(_) => None, String(s) => match f64::from_str(s) { Ok(x) => number_to_index(x), Err(_) => None, @@ -216,6 +223,7 @@ impl ValTrait for Val { Bool(_) => true, Number(_) => true, BigInt(_) => true, + Symbol(_) => true, String(_) => true, Array(_) => false, Object(_) => false, @@ -244,6 +252,7 @@ impl ValTrait for Val { Bool(b) => *b, Number(x) => *x != 0_f64 && !x.is_nan(), BigInt(x) => !x.is_zero(), + Symbol(_) => true, String(s) => s.len() > 0, Array(_) => true, Object(_) => true, @@ -264,6 +273,7 @@ impl ValTrait for Val { Bool(_) => false, Number(_) => false, BigInt(_) => false, + Symbol(_) => false, String(_) => false, Array(_) => false, Object(_) => false, @@ -364,6 +374,7 @@ impl ValTrait for Val { Val::Bool(_) => self.val_to_string(), Val::Number(_) => self.val_to_string(), Val::BigInt(_) => self.val_to_string() + "n", + Val::Symbol(s) => format!("Symbol.{}", symbol_to_name(s.clone())), Val::String(str) => stringify_string(str), Val::Array(vals) => { if vals.elements.len() == 0 { @@ -441,6 +452,7 @@ impl std::fmt::Display for Val { Val::Bool(_) => write!(f, "\x1b[33m{}\x1b[39m", self.val_to_string()), Val::Number(_) => write!(f, "\x1b[33m{}\x1b[39m", self.val_to_string()), Val::BigInt(_) => write!(f, "\x1b[33m{}n\x1b[39m", self.val_to_string()), + Val::Symbol(_) => write!(f, "\x1b[32m{}\x1b[39m", self.codify()), Val::String(_) => write!(f, "\x1b[32m{}\x1b[39m", self.codify()), Val::Array(array) => { if array.elements.len() == 0 {