diff --git a/crates/dash_middle/src/interner.rs b/crates/dash_middle/src/interner.rs index 753e907c..a8f27de3 100644 --- a/crates/dash_middle/src/interner.rs +++ b/crates/dash_middle/src/interner.rs @@ -251,11 +251,13 @@ pub mod sym { Promise, then, Set, + WeakSet, add, has, clear, size, Map, + WeakMap, RegExp, test, exec, diff --git a/crates/dash_vm/src/js_std/mod.rs b/crates/dash_vm/src/js_std/mod.rs index b0f50873..77d76ac2 100755 --- a/crates/dash_vm/src/js_std/mod.rs +++ b/crates/dash_vm/src/js_std/mod.rs @@ -22,6 +22,8 @@ pub mod set; pub mod string; pub mod symbol; pub mod typedarray; +pub mod weakmap; +pub mod weakset; pub fn receiver_t<'a, T: 'static>( sc: &mut LocalScope<'_>, diff --git a/crates/dash_vm/src/js_std/weakmap.rs b/crates/dash_vm/src/js_std/weakmap.rs new file mode 100644 index 00000000..b5de5b7b --- /dev/null +++ b/crates/dash_vm/src/js_std/weakmap.rs @@ -0,0 +1,65 @@ +use dash_middle::interner::sym; + +use crate::throw; +use crate::value::function::native::CallContext; +use crate::value::object::{NamedObject, PropertyKey}; +use crate::value::ops::conversions::ValueConversion; +use crate::value::weakmap::WeakMap; +use crate::value::{Root, Value, ValueContext}; + +use super::receiver_t; + +pub fn constructor(cx: CallContext) -> Result { + let Some(new_target) = cx.new_target else { + throw!(cx.scope, TypeError, "WeakMap constructor requires new") + }; + + let weakmap = WeakMap::with_obj(NamedObject::instance_for_new_target(new_target, cx.scope)?); + if let Some(iter) = cx.args.first() { + let len = iter.length_of_array_like(cx.scope)?; + + for i in 0..len { + let i = cx.scope.intern_usize(i); + let item = iter + .get_property(cx.scope, PropertyKey::String(i.into())) + .root(cx.scope)?; + let k = item + .get_property(cx.scope, PropertyKey::String(sym::zero.into())) + .root(cx.scope)?; + let v = item + .get_property(cx.scope, PropertyKey::String(sym::one.into())) + .root(cx.scope)?; + weakmap.set(k, v); + } + } + + Ok(Value::object(cx.scope.register(weakmap))) +} + +pub fn set(cx: CallContext) -> Result { + let k = cx.args.first().unwrap_or_undefined(); + let v = cx.args.get(1).unwrap_or_undefined(); + receiver_t::(cx.scope, &cx.this, "WeakMap.prototype.set")?.set(k, v); + + Ok(cx.this) +} + +pub fn has(cx: CallContext) -> Result { + let item = cx.args.first().unwrap_or_undefined(); + Ok(Value::boolean( + receiver_t::(cx.scope, &cx.this, "WeakMap.prototype.has")?.has(&item), + )) +} + +pub fn get(cx: CallContext) -> Result { + let item = cx.args.first().unwrap_or_undefined(); + Ok(receiver_t::(cx.scope, &cx.this, "WeakMap.prototype.get")? + .get(&item) + .unwrap_or_undefined()) +} + +pub fn delete(cx: CallContext) -> Result { + let item = cx.args.first().unwrap_or_undefined(); + let did_delete = receiver_t::(cx.scope, &cx.this, "WeakMap.prototype.delete")?.delete(&item); + Ok(Value::boolean(did_delete)) +} diff --git a/crates/dash_vm/src/js_std/weakset.rs b/crates/dash_vm/src/js_std/weakset.rs new file mode 100644 index 00000000..79693745 --- /dev/null +++ b/crates/dash_vm/src/js_std/weakset.rs @@ -0,0 +1,51 @@ +use crate::throw; +use crate::value::function::native::CallContext; +use crate::value::object::{NamedObject, PropertyKey}; +use crate::value::ops::conversions::ValueConversion; +use crate::value::weakset::WeakSet; +use crate::value::{Root, Value, ValueContext}; + +use super::receiver_t; + +pub fn constructor(cx: CallContext) -> Result { + let Some(new_target) = cx.new_target else { + throw!(cx.scope, TypeError, "WeakSet constructor requires new") + }; + + let weakset = WeakSet::with_obj(NamedObject::instance_for_new_target(new_target, cx.scope)?); + if let Some(iter) = cx.args.first() { + let len = iter.length_of_array_like(cx.scope)?; + + for i in 0..len { + let i = cx.scope.intern_usize(i); + let item = iter + .get_property(cx.scope, PropertyKey::String(i.into())) + .root(cx.scope)?; + + weakset.add(item); + } + } + + Ok(Value::object(cx.scope.register(weakset))) +} + +pub fn add(cx: CallContext) -> Result { + let item = cx.args.first().unwrap_or_undefined(); + receiver_t::(cx.scope, &cx.this, "WeakSet.prototype.add")?.add(item); + + Ok(cx.this) +} + +pub fn has(cx: CallContext) -> Result { + let item = cx.args.first().unwrap_or_undefined(); + Ok(Value::boolean( + receiver_t::(cx.scope, &cx.this, "WeakSet.prototype.has")?.has(&item), + )) +} + +pub fn delete(cx: CallContext) -> Result { + let item = cx.args.first().unwrap_or_undefined(); + let did_delete = receiver_t::(cx.scope, &cx.this, "WeakSet.prototype.delete")?.delete(&item); + + Ok(Value::boolean(did_delete)) +} diff --git a/crates/dash_vm/src/lib.rs b/crates/dash_vm/src/lib.rs index 6ab9dce1..8d77fe3e 100644 --- a/crates/dash_vm/src/lib.rs +++ b/crates/dash_vm/src/lib.rs @@ -885,6 +885,59 @@ impl Vm { &mut scope, ); + let weakmap_ctor = register( + scope.statics.weakmap_constructor, + function_proto, + function_ctor, + [], + [], + [], + Some((sym::WeakMap, scope.statics.weakmap_prototype)), + &mut scope + ); + + register( + scope.statics.weakmap_prototype, + object_proto, + weakmap_ctor, + [ + (sym::set, scope.statics.weakmap_set), + (sym::has, scope.statics.weakmap_has), + (sym::get, scope.statics.weakmap_get), + (sym::delete, scope.statics.weakmap_delete), + ], + [], + [], + None, + &mut scope + ); + + let weakset_ctor = register( + scope.statics.weakset_constructor, + function_proto, + function_ctor, + [], + [], + [], + Some((sym::WeakSet, scope.statics.weakset_prototype)), + &mut scope + ); + + register( + scope.statics.weakset_prototype, + object_proto, + weakset_ctor, + [ + (sym::add, scope.statics.weakset_add), + (sym::has, scope.statics.weakset_has), + (sym::delete, scope.statics.weakset_delete), + ], + [], + [], + None, + &mut scope + ); + let regexp_ctor = register( scope.statics.regexp_ctor, function_proto, @@ -1152,6 +1205,8 @@ impl Vm { (sym::Object, object_ctor), (sym::Set, set_ctor), (sym::Map, map_ctor), + (sym::WeakMap, weakmap_ctor), + (sym::WeakSet, weakset_ctor), (sym::console, console), (sym::Math, math), (sym::Number, number_ctor), diff --git a/crates/dash_vm/src/statics.rs b/crates/dash_vm/src/statics.rs index 92f56daa..f5477920 100644 --- a/crates/dash_vm/src/statics.rs +++ b/crates/dash_vm/src/statics.rs @@ -8,6 +8,8 @@ use crate::value::function::{Function, FunctionKind}; use crate::value::map::Map; use crate::value::regex::RegExp; use crate::value::set::Set; +use crate::value::weakmap::WeakMap; +use crate::value::weakset::WeakSet; use dash_middle::interner::{self, sym}; use super::value::array::{Array, ArrayIterator}; @@ -246,6 +248,17 @@ pub struct Statics { pub map_delete: ObjectId, pub map_clear: ObjectId, pub map_size: ObjectId, + pub weakmap_constructor: ObjectId, + pub weakmap_prototype: ObjectId, + pub weakmap_set: ObjectId, + pub weakmap_has: ObjectId, + pub weakmap_get: ObjectId, + pub weakmap_delete: ObjectId, + pub weakset_constructor: ObjectId, + pub weakset_prototype: ObjectId, + pub weakset_add: ObjectId, + pub weakset_has: ObjectId, + pub weakset_delete: ObjectId, pub regexp_ctor: ObjectId, pub regexp_prototype: ObjectId, pub regexp_test: ObjectId, @@ -525,6 +538,17 @@ impl Statics { date_get_time: function(gc, sym::getTime, js_std::date::get_time), json_ctor: function(gc, sym::JSON, js_std::json::constructor), json_parse: function(gc, sym::parse, js_std::json::parse), + weakmap_constructor: function(gc, sym::WeakMap, js_std::weakmap::constructor), + weakmap_prototype: builtin_object(gc, WeakMap::null()), + weakmap_set: function(gc, sym::set, js_std::weakmap::set), + weakmap_has: function(gc, sym::has, js_std::weakmap::has), + weakmap_get: function(gc, sym::get, js_std::weakmap::get), + weakmap_delete: function(gc, sym::delete, js_std::weakmap::delete), + weakset_constructor: function(gc, sym::WeakSet, js_std::weakset::constructor), + weakset_prototype: builtin_object(gc, WeakSet::null()), + weakset_add: function(gc, sym::add, js_std::weakset::add), + weakset_has: function(gc, sym::has, js_std::weakset::has), + weakset_delete: function(gc, sym::delete, js_std::weakset::delete), } } } diff --git a/crates/dash_vm/src/value/mod.rs b/crates/dash_vm/src/value/mod.rs index 9a668556..191e9c6d 100755 --- a/crates/dash_vm/src/value/mod.rs +++ b/crates/dash_vm/src/value/mod.rs @@ -14,6 +14,8 @@ pub mod promise; pub mod regex; pub mod set; pub mod typedarray; +pub mod weakmap; +pub mod weakset; use std::any::TypeId; use std::ops::ControlFlow; diff --git a/crates/dash_vm/src/value/weakmap.rs b/crates/dash_vm/src/value/weakmap.rs new file mode 100644 index 00000000..d2ecd899 --- /dev/null +++ b/crates/dash_vm/src/value/weakmap.rs @@ -0,0 +1,58 @@ +use dash_proc_macro::Trace; + +use crate::{delegate, extract}; + +use super::Value; +use super::map::Map; +use super::object::{NamedObject, Object}; + +#[derive(Debug, Trace)] +pub struct WeakMap { + // for now + map: Map, +} + +impl WeakMap { + pub fn with_obj(object: NamedObject) -> Self { + Self { + map: Map::with_obj(object), + } + } + + pub fn null() -> Self { + Self::with_obj(NamedObject::null()) + } + + pub fn set(&self, key: Value, value: Value) { + self.map.set(key, value); + } + + pub fn delete(&self, key: &Value) -> bool { + self.map.delete(key) + } + + pub fn get(&self, key: &Value) -> Option { + self.map.get(key) + } + + pub fn has(&self, key: &Value) -> bool { + self.map.has(key) + } +} + +impl Object for WeakMap { + delegate!( + map, + get_own_property_descriptor, + get_property, + get_property_descriptor, + set_property, + delete_property, + set_prototype, + get_prototype, + apply, + own_keys + ); + + extract!(self); +} diff --git a/crates/dash_vm/src/value/weakset.rs b/crates/dash_vm/src/value/weakset.rs new file mode 100644 index 00000000..767e7afb --- /dev/null +++ b/crates/dash_vm/src/value/weakset.rs @@ -0,0 +1,54 @@ +use dash_proc_macro::Trace; + +use crate::{delegate, extract}; + +use super::Value; +use super::object::{NamedObject, Object}; +use super::set::Set; + +#[derive(Debug, Trace)] +pub struct WeakSet { + // for now + set: Set, +} + +impl WeakSet { + pub fn with_obj(object: NamedObject) -> Self { + Self { + set: Set::with_obj(object), + } + } + + pub fn null() -> Self { + Self::with_obj(NamedObject::null()) + } + + pub fn add(&self, key: Value) { + self.set.add(key); + } + + pub fn delete(&self, key: &Value) -> bool { + self.set.delete(key) + } + + pub fn has(&self, key: &Value) -> bool { + self.set.has(key) + } +} + +impl Object for WeakSet { + delegate!( + set, + get_own_property_descriptor, + get_property, + get_property_descriptor, + set_property, + delete_property, + set_prototype, + get_prototype, + apply, + own_keys + ); + + extract!(self); +}