1- use crate :: core:: JSWeakMap ;
2- use crate :: core:: { Collect , Gc , GcCell , GcPtr , MutationContext , Trace } ;
1+ use crate :: core:: { Gc , GcCell , MutationContext } ;
2+ use crate :: core:: { JSWeakMap , PropertyKey } ;
33use crate :: {
4- core:: { Expr , JSObjectDataPtr , Value , evaluate_expr , obj_get_key_value} ,
4+ core:: { JSObjectDataPtr , Value , env_set , new_js_object_data , obj_get_key_value, obj_set_key_value } ,
55 error:: JSError ,
66 unicode:: utf8_to_utf16,
77} ;
88
99/// Handle WeakMap constructor calls
1010pub ( crate ) fn handle_weakmap_constructor < ' gc > (
1111 mc : & MutationContext < ' gc > ,
12- args : & [ Expr ] ,
12+ args : & [ Value < ' gc > ] ,
1313 env : & JSObjectDataPtr < ' gc > ,
1414) -> Result < Value < ' gc > , JSError > {
1515 let weakmap = Gc :: new ( mc, GcCell :: new ( JSWeakMap { entries : Vec :: new ( ) } ) ) ;
1616
1717 if !args. is_empty ( ) {
1818 if args. len ( ) == 1 {
19- // WeakMap(iterable)
20- initialize_weakmap_from_iterable ( mc, & weakmap, args, env ) ?;
19+ // WeakMap(iterable) - args are already evaluated values
20+ initialize_weakmap_from_iterable ( mc, & weakmap, & args[ 0 ] ) ?;
2121 } else {
2222 return Err ( raise_eval_error ! ( "WeakMap constructor takes at most one argument" ) ) ;
2323 }
2424 }
2525
26- Ok ( Value :: WeakMap ( weakmap) )
26+ // Create a wrapper object for the WeakMap
27+ let weakmap_obj = new_js_object_data ( mc) ;
28+ // Store the actual weakmap data
29+ weakmap_obj. borrow_mut ( mc) . insert (
30+ PropertyKey :: String ( "__weakmap__" . to_string ( ) ) ,
31+ Gc :: new ( mc, GcCell :: new ( Value :: WeakMap ( weakmap) ) ) ,
32+ ) ;
33+
34+ // Set prototype to WeakMap.prototype if available
35+ if let Some ( weakmap_ctor) = obj_get_key_value ( env, & "WeakMap" . into ( ) ) ?
36+ && let Value :: Object ( ctor) = & * weakmap_ctor. borrow ( )
37+ && let Some ( proto) = obj_get_key_value ( ctor, & "prototype" . into ( ) ) ?
38+ && let Value :: Object ( proto_obj) = & * proto. borrow ( )
39+ {
40+ weakmap_obj. borrow_mut ( mc) . prototype = Some ( proto_obj. clone ( ) ) ;
41+ }
42+
43+ Ok ( Value :: Object ( weakmap_obj) )
2744}
2845
2946/// Initialize WeakMap from an iterable
3047fn initialize_weakmap_from_iterable < ' gc > (
3148 mc : & MutationContext < ' gc > ,
3249 weakmap : & Gc < ' gc , GcCell < JSWeakMap < ' gc > > > ,
33- args : & [ Expr ] ,
34- env : & JSObjectDataPtr < ' gc > ,
50+ iterable : & Value < ' gc > ,
3551) -> Result < ( ) , JSError > {
36- let iterable = evaluate_expr ( mc, env, & args[ 0 ] ) ?;
3752 match iterable {
3853 Value :: Object ( obj) => {
3954 let mut i = 0 ;
@@ -72,8 +87,48 @@ fn initialize_weakmap_from_iterable<'gc>(
7287 Ok ( ( ) )
7388}
7489
90+ /// Initialize WeakMap constructor and prototype
91+ pub fn initialize_weakmap < ' gc > ( mc : & MutationContext < ' gc > , env : & JSObjectDataPtr < ' gc > ) -> Result < ( ) , JSError > {
92+ let weakmap_ctor = new_js_object_data ( mc) ;
93+ obj_set_key_value ( mc, & weakmap_ctor, & "__is_constructor" . into ( ) , Value :: Boolean ( true ) ) ?;
94+ obj_set_key_value ( mc, & weakmap_ctor, & "__native_ctor" . into ( ) , Value :: String ( utf8_to_utf16 ( "WeakMap" ) ) ) ?;
95+
96+ // Get Object.prototype
97+ let object_proto = if let Some ( obj_val) = obj_get_key_value ( env, & "Object" . into ( ) ) ?
98+ && let Value :: Object ( obj_ctor) = & * obj_val. borrow ( )
99+ && let Some ( proto_val) = obj_get_key_value ( obj_ctor, & "prototype" . into ( ) ) ?
100+ && let Value :: Object ( proto) = & * proto_val. borrow ( )
101+ {
102+ Some ( * proto)
103+ } else {
104+ None
105+ } ;
106+
107+ let weakmap_proto = new_js_object_data ( mc) ;
108+ if let Some ( proto) = object_proto {
109+ weakmap_proto. borrow_mut ( mc) . prototype = Some ( proto) ;
110+ }
111+
112+ obj_set_key_value ( mc, & weakmap_ctor, & "prototype" . into ( ) , Value :: Object ( weakmap_proto. clone ( ) ) ) ?;
113+ obj_set_key_value ( mc, & weakmap_proto, & "constructor" . into ( ) , Value :: Object ( weakmap_ctor. clone ( ) ) ) ?;
114+
115+ // Register instance methods
116+ let methods = vec ! [ "set" , "get" , "has" , "delete" , "toString" ] ;
117+
118+ for method in methods {
119+ let val = Value :: Function ( format ! ( "WeakMap.prototype.{method}" ) ) ;
120+ obj_set_key_value ( mc, & weakmap_proto, & method. into ( ) , val) ?;
121+ weakmap_proto. borrow_mut ( mc) . set_non_enumerable ( PropertyKey :: from ( method) ) ;
122+ }
123+ // Mark constructor non-enumerable
124+ weakmap_proto. borrow_mut ( mc) . set_non_enumerable ( PropertyKey :: from ( "constructor" ) ) ;
125+
126+ env_set ( mc, env, "WeakMap" , Value :: Object ( weakmap_ctor) ) ?;
127+ Ok ( ( ) )
128+ }
129+
75130/// Check if WeakMap has a key
76- fn weakmap_has_key < ' gc > ( weakmap : & Gc < ' gc , GcCell < JSWeakMap < ' gc > > > , key_obj_rc : & JSObjectDataPtr < ' gc > ) -> bool {
131+ fn weakmap_has_key < ' gc > ( mc : & MutationContext < ' gc > , weakmap : & Gc < ' gc , GcCell < JSWeakMap < ' gc > > > , key_obj_rc : & JSObjectDataPtr < ' gc > ) -> bool {
77132 let weakmap = weakmap. borrow ( ) ;
78133 for ( k, _) in & weakmap. entries {
79134 if k. upgrade ( mc) . map_or ( false , |p| Gc :: ptr_eq ( p, * key_obj_rc) ) {
@@ -102,16 +157,16 @@ pub(crate) fn handle_weakmap_instance_method<'gc>(
102157 mc : & MutationContext < ' gc > ,
103158 weakmap : & Gc < ' gc , GcCell < JSWeakMap < ' gc > > > ,
104159 method : & str ,
105- args : & [ Expr ] ,
106- env : & JSObjectDataPtr < ' gc > ,
160+ args : & [ Value < ' gc > ] ,
161+ _env : & JSObjectDataPtr < ' gc > ,
107162) -> Result < Value < ' gc > , JSError > {
108163 match method {
109164 "set" => {
110165 if args. len ( ) != 2 {
111166 return Err ( raise_eval_error ! ( "WeakMap.prototype.set requires exactly two arguments" ) ) ;
112167 }
113- let key = evaluate_expr ( mc , env , & args[ 0 ] ) ? ;
114- let value = evaluate_expr ( mc , env , & args[ 1 ] ) ? ;
168+ let key = args[ 0 ] . clone ( ) ;
169+ let value = args[ 1 ] . clone ( ) ;
115170
116171 // Check if key is an object
117172 let key_obj_rc = match key {
@@ -134,7 +189,7 @@ pub(crate) fn handle_weakmap_instance_method<'gc>(
134189 if args. len ( ) != 1 {
135190 return Err ( raise_eval_error ! ( "WeakMap.prototype.get requires exactly one argument" ) ) ;
136191 }
137- let key = evaluate_expr ( mc , env , & args[ 0 ] ) ? ;
192+ let key = args[ 0 ] . clone ( ) ;
138193
139194 let key_obj_rc = match key {
140195 Value :: Object ( ref obj) => obj,
@@ -154,20 +209,20 @@ pub(crate) fn handle_weakmap_instance_method<'gc>(
154209 if args. len ( ) != 1 {
155210 return Err ( raise_eval_error ! ( "WeakMap.prototype.has requires exactly one argument" ) ) ;
156211 }
157- let key = evaluate_expr ( mc , env , & args[ 0 ] ) ? ;
212+ let key = args[ 0 ] . clone ( ) ;
158213
159214 let key_obj_rc = match key {
160215 Value :: Object ( ref obj) => obj,
161216 _ => return Ok ( Value :: Boolean ( false ) ) ,
162217 } ;
163218
164- Ok ( Value :: Boolean ( weakmap_has_key ( weakmap, key_obj_rc) ) )
219+ Ok ( Value :: Boolean ( weakmap_has_key ( mc , weakmap, key_obj_rc) ) )
165220 }
166221 "delete" => {
167222 if args. len ( ) != 1 {
168223 return Err ( raise_eval_error ! ( "WeakMap.prototype.delete requires exactly one argument" ) ) ;
169224 }
170- let key = evaluate_expr ( mc , env , & args[ 0 ] ) ? ;
225+ let key = args[ 0 ] . clone ( ) ;
171226
172227 let key_obj_rc = match key {
173228 Value :: Object ( ref obj) => obj,
0 commit comments