diff --git a/Cargo.lock b/Cargo.lock index 8f16baa..b6febc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2386,6 +2386,7 @@ version = "0.1.0" dependencies = [ "num-bigint", "num-traits", + "storage", "valuescript_common", ] diff --git a/storage/src/demo_val.rs b/storage/src/demo_val.rs index 51ec60c..68d3e7b 100644 --- a/storage/src/demo_val.rs +++ b/storage/src/demo_val.rs @@ -136,8 +136,6 @@ impl StorageEntity for DemoVal { } fn from_storage_entry>(tx: &mut Tx, entry: StorageEntry) -> Result { - let mut reader = StorageEntryReader::new(&entry); - - Self::read_from_entry(tx, &mut reader) + Self::read_from_entry(tx, &mut StorageEntryReader::new(&entry)) } } diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 6fe8732..bc7abb2 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -17,5 +17,7 @@ pub use self::storage::Storage; pub use self::storage_backend::StorageBackend; pub use memory_backend::MemoryBackend; pub use sled_backend::SledBackend; +pub use storage_entity::StorageEntity; pub use storage_entry::{StorageEntry, StorageEntryReader}; -pub use storage_ptr::{storage_head_ptr, StoragePtr}; +pub use storage_ops::StorageOps; +pub use storage_ptr::{storage_head_ptr, StorageEntryPtr, StorageHeadPtr, StoragePtr}; diff --git a/storage/src/storage_entry.rs b/storage/src/storage_entry.rs index 809c865..da67350 100644 --- a/storage/src/storage_entry.rs +++ b/storage/src/storage_entry.rs @@ -5,8 +5,8 @@ use crate::storage_ptr::StorageEntryPtr; #[derive(Serialize, Deserialize)] pub struct StorageEntry { pub(crate) ref_count: u64, - pub(crate) refs: Vec, - pub(crate) data: Vec, + pub refs: Vec, + pub data: Vec, } pub struct StorageEntryReader<'a> { diff --git a/valuescript_compiler/src/optimization/try_to_kal.rs b/valuescript_compiler/src/optimization/try_to_kal.rs index 434279f..2109442 100644 --- a/valuescript_compiler/src/optimization/try_to_kal.rs +++ b/valuescript_compiler/src/optimization/try_to_kal.rs @@ -62,6 +62,7 @@ impl TryToKal for Val { | Val::Static(..) | Val::Dynamic(..) | Val::CopyCounter(..) => return None, + Val::StoragePtr(ptr) => return ptr.get().try_to_kal(), }) } } diff --git a/valuescript_vm/Cargo.toml b/valuescript_vm/Cargo.toml index 2c3f016..664623d 100644 --- a/valuescript_vm/Cargo.toml +++ b/valuescript_vm/Cargo.toml @@ -9,3 +9,4 @@ edition = "2021" num-bigint = "0.4" num-traits = "0.2" valuescript_common = { path = "../valuescript_common" } +storage = { path = "../storage" } diff --git a/valuescript_vm/src/builtins/array_builtin.rs b/valuescript_vm/src/builtins/array_builtin.rs index a1bd2d1..04bf5f7 100644 --- a/valuescript_vm/src/builtins/array_builtin.rs +++ b/valuescript_vm/src/builtins/array_builtin.rs @@ -55,15 +55,19 @@ static IS_ARRAY: NativeFunction = native_fn(|_this, params| { }); static FROM: NativeFunction = native_fn(|_this, params| { - let first_param = match params.get(0) { + let mut first_param = match params.get(0) { None => return Err("undefined is not iterable".to_type_error()), - Some(p) => p, + Some(p) => p.clone(), }; if params.len() > 1 { return Err("TODO: Using Array.from with a map function".to_internal_error()); } + if let Val::StoragePtr(ptr) = first_param { + first_param = ptr.get(); + } + Ok(match first_param { Val::Array(arr) => Val::Array(arr.clone()), Val::String(s) => s.chars().map(|c| c.to_val()).collect::>().to_val(), @@ -104,6 +108,9 @@ static FROM: NativeFunction = native_fn(|_this, params| { VsArray::from(arr).to_val() } + Val::StoragePtr(_) => { + panic!("Shouldn't be possible") // prevented this just above the match + } }) }); diff --git a/valuescript_vm/src/lib.rs b/valuescript_vm/src/lib.rs index 2682080..4b12174 100644 --- a/valuescript_vm/src/lib.rs +++ b/valuescript_vm/src/lib.rs @@ -19,11 +19,13 @@ pub mod operations; mod stack_frame; mod string_methods; mod todo_fn; +mod val_storage; mod virtual_machine; pub mod vs_array; pub mod vs_class; mod vs_function; pub mod vs_object; +mod vs_storage_ptr; mod vs_symbol; pub mod vs_value; diff --git a/valuescript_vm/src/operations.rs b/valuescript_vm/src/operations.rs index 92fabd0..54335a9 100644 --- a/valuescript_vm/src/operations.rs +++ b/valuescript_vm/src/operations.rs @@ -636,6 +636,7 @@ pub fn op_sub(left: &mut Val, right: &Val) -> Result { "count" => (*cc.count.borrow() as f64).to_val(), _ => Val::Undefined, }), + Val::StoragePtr(ptr) => ptr.get().sub(right), } } @@ -692,6 +693,13 @@ pub fn op_submov(target: &mut Val, subscript: &Val, value: Val) -> Result<(), Va Val::Static(_) => Err("Cannot assign to subscript of static value".to_type_error()), Val::Dynamic(_) => Err("TODO: Assign to subscript of dynamic value".to_type_error()), Val::CopyCounter(_) => Err("Cannot assign to subscript of CopyCounter".to_type_error()), + Val::StoragePtr(ptr) => { + let mut val = ptr.get(); + val.submov(subscript, value)?; + *target = val; + + Ok(()) + } } } diff --git a/valuescript_vm/src/val_storage.rs b/valuescript_vm/src/val_storage.rs new file mode 100644 index 0000000..b31ad32 --- /dev/null +++ b/valuescript_vm/src/val_storage.rs @@ -0,0 +1,176 @@ +use storage::{StorageEntity, StorageEntry, StorageEntryReader, StorageOps}; + +use crate::vs_value::Val; + +enum Tag { + Void, + Undefined, + Null, + Bool, + Number, + BigInt, + Symbol, + String, + Array, + Object, + Function, + Class, + Static, + Dynamic, + CopyCounter, +} + +impl Tag { + fn to_byte(&self) -> u8 { + match self { + Tag::Void => 0, + Tag::Undefined => 1, + Tag::Null => 2, + Tag::Bool => 3, + Tag::Number => 4, + Tag::BigInt => 5, + Tag::Symbol => 6, + Tag::String => 7, + Tag::Array => 8, + Tag::Object => 9, + Tag::Function => 10, + Tag::Class => 11, + Tag::Static => 12, + Tag::Dynamic => 13, + Tag::CopyCounter => 14, + } + } + + fn from_byte(byte: u8) -> Self { + match byte { + 0 => Tag::Void, + 1 => Tag::Undefined, + 2 => Tag::Null, + 3 => Tag::Bool, + 4 => Tag::Number, + 5 => Tag::BigInt, + 6 => Tag::Symbol, + 7 => Tag::String, + 8 => Tag::Array, + 9 => Tag::Object, + 10 => Tag::Function, + 11 => Tag::Class, + 12 => Tag::Static, + 13 => Tag::Dynamic, + 14 => Tag::CopyCounter, + _ => panic!("Invalid tag byte: {}", byte), + } + } +} + +impl StorageEntity for Val { + fn from_storage_entry>(tx: &mut Tx, entry: StorageEntry) -> Result { + read_from_entry(tx, &mut StorageEntryReader::new(&entry)) + // TODO: assert that we've read the whole entry + } + + fn to_storage_entry>(&self, tx: &mut Tx) -> Result { + todo!() + } +} + +fn write_to_entry>( + val: &Val, + tx: &mut SO, + entry: &mut StorageEntry, +) -> Result<(), E> { + match val { + Val::Void => { + entry.data.push(Tag::Void.to_byte()); + } + Val::Undefined => { + entry.data.push(Tag::Undefined.to_byte()); + } + Val::Null => { + entry.data.push(Tag::Null.to_byte()); + } + Val::Bool(b) => { + entry.data.push(Tag::Bool.to_byte()); + entry.data.push(if *b { 1 } else { 0 }); + } + Val::Number(n) => { + entry.data.push(Tag::Number.to_byte()); + entry.data.extend_from_slice(&n.to_le_bytes()); + } + Val::BigInt(b) => { + entry.data.push(Tag::BigInt.to_byte()); + todo!() + } + Val::Symbol(s) => { + entry.data.push(Tag::Symbol.to_byte()); + todo!() + } + Val::String(s) => { + entry.data.push(Tag::String.to_byte()); + todo!() + } + Val::Array(a) => { + entry.data.push(Tag::Array.to_byte()); + todo!() + } + Val::Object(o) => { + entry.data.push(Tag::Object.to_byte()); + todo!() + } + Val::Function(f) => { + entry.data.push(Tag::Function.to_byte()); + todo!() + } + Val::Class(c) => { + entry.data.push(Tag::Class.to_byte()); + todo!() + } + Val::Static(s) => { + entry.data.push(Tag::Static.to_byte()); + todo!() + } + Val::Dynamic(d) => { + entry.data.push(Tag::Dynamic.to_byte()); + todo!() + } + Val::CopyCounter(cc) => { + entry.data.push(Tag::CopyCounter.to_byte()); + todo!() + } + Val::StoragePtr(ptr) => { + entry.data.push(Tag::CopyCounter.to_byte()); + todo!() + } + }; + + Ok(()) +} + +fn read_from_entry>( + _tx: &mut SO, + reader: &mut StorageEntryReader, +) -> Result { + let tag = Tag::from_byte(reader.read_u8().unwrap()); + + Ok(match tag { + Tag::Void => Val::Void, + Tag::Undefined => Val::Undefined, + Tag::Null => Val::Null, + Tag::Bool => Val::Bool(match reader.read_u8().unwrap() { + 0 => false, + 1 => true, + _ => panic!("Invalid bool byte"), + }), + Tag::Number => todo!(), + Tag::BigInt => todo!(), + Tag::Symbol => todo!(), + Tag::String => todo!(), + Tag::Array => todo!(), + Tag::Object => todo!(), + Tag::Function => todo!(), + Tag::Class => todo!(), + Tag::Static => todo!(), + Tag::Dynamic => todo!(), + Tag::CopyCounter => todo!(), + }) +} diff --git a/valuescript_vm/src/vs_storage_ptr.rs b/valuescript_vm/src/vs_storage_ptr.rs new file mode 100644 index 0000000..b4224d6 --- /dev/null +++ b/valuescript_vm/src/vs_storage_ptr.rs @@ -0,0 +1,27 @@ +use std::{cell::RefCell, fmt::Debug}; + +use storage::StorageEntryPtr; + +use crate::vs_value::Val; + +#[derive(Debug)] +pub struct VsStoragePtr { + ptr: StorageEntryPtr, + cache: RefCell>, +} + +impl VsStoragePtr { + pub fn get(&self) -> Val { + #[allow(unused_mut)] // Used in commented code + let mut cache = self.cache.borrow_mut(); + + if let Some(val) = &*cache { + return val.clone(); + } + + todo!() + // let val = /* TODO */; + // *cache = Some(val.clone()); + // val + } +} diff --git a/valuescript_vm/src/vs_value.rs b/valuescript_vm/src/vs_value.rs index ea71830..597f952 100644 --- a/valuescript_vm/src/vs_value.rs +++ b/valuescript_vm/src/vs_value.rs @@ -16,6 +16,7 @@ use crate::vs_array::VsArray; use crate::vs_class::VsClass; use crate::vs_function::VsFunction; use crate::vs_object::VsObject; +use crate::vs_storage_ptr::VsStoragePtr; use crate::vs_symbol::{symbol_to_name, VsSymbol}; #[derive(Clone, Debug, Default)] @@ -36,6 +37,7 @@ pub enum Val { Static(&'static dyn ValTrait), Dynamic(Rc), CopyCounter(Box), + StoragePtr(Rc), } #[derive(PartialEq, Debug)] @@ -185,6 +187,7 @@ impl ValTrait for Val { Static(val) => val.typeof_(), Dynamic(val) => val.typeof_(), CopyCounter(_) => VsType::Object, + StoragePtr(ptr) => ptr.get().typeof_(), } } @@ -211,6 +214,7 @@ impl ValTrait for Val { Static(val) => val.to_number(), Dynamic(val) => val.to_number(), CopyCounter(_) => f64::NAN, + StoragePtr(ptr) => ptr.get().to_number(), } } @@ -236,6 +240,7 @@ impl ValTrait for Val { Static(val) => val.to_index(), Dynamic(val) => val.to_index(), CopyCounter(_) => None, + StoragePtr(ptr) => ptr.get().to_index(), } } @@ -258,6 +263,7 @@ impl ValTrait for Val { Static(val) => val.is_primitive(), // TODO: false? Dynamic(val) => val.is_primitive(), CopyCounter(_) => false, + StoragePtr(ptr) => ptr.get().is_primitive(), } } @@ -280,6 +286,7 @@ impl ValTrait for Val { Static(val) => val.is_truthy(), // TODO: true? Dynamic(val) => val.is_truthy(), CopyCounter(_) => true, + StoragePtr(ptr) => ptr.get().is_truthy(), } } @@ -302,6 +309,7 @@ impl ValTrait for Val { Static(_) => false, Dynamic(val) => val.is_nullish(), CopyCounter(_) => false, + StoragePtr(ptr) => ptr.get().is_nullish(), } } @@ -454,6 +462,7 @@ impl ValTrait for Val { Val::Static(static_) => static_.has(key), Val::Dynamic(dynamic) => dynamic.has(key), Val::CopyCounter(_) => Some(matches!(key.to_string().as_str(), "tag" | "count")), + Val::StoragePtr(ptr) => ptr.get().has(key), } } @@ -540,6 +549,7 @@ impl ValTrait for Val { cc.tag.codify(), cc.count.borrow() ), + Val::StoragePtr(_) => todo!(), } } } @@ -601,6 +611,7 @@ impl fmt::Display for Val { cc.tag, (*cc.count.borrow() as f64).to_val() ), + StoragePtr(ptr) => ptr.get().fmt(f), } } } @@ -771,6 +782,8 @@ impl<'a> std::fmt::Display for PrettyVal<'a> { cc.tag.pretty(), (*cc.count.borrow() as f64).to_val().pretty() ), + + Val::StoragePtr(ptr) => ptr.get().pretty_fmt(f), } } }