1 package goja
2
3 import (
4 "reflect"
5 )
6
7 var mapExportType = reflect.TypeOf([][2]interface{}{})
8
9 type mapObject struct {
10 baseObject
11 m *orderedMap
12 }
13
14 type mapIterObject struct {
15 baseObject
16 iter *orderedMapIter
17 kind iterationKind
18 }
19
20 func (o *mapIterObject) next() Value {
21 if o.iter == nil {
22 return o.val.runtime.createIterResultObject(_undefined, true)
23 }
24
25 entry := o.iter.next()
26 if entry == nil {
27 o.iter = nil
28 return o.val.runtime.createIterResultObject(_undefined, true)
29 }
30
31 var result Value
32 switch o.kind {
33 case iterationKindKey:
34 result = entry.key
35 case iterationKindValue:
36 result = entry.value
37 default:
38 result = o.val.runtime.newArrayValues([]Value{entry.key, entry.value})
39 }
40
41 return o.val.runtime.createIterResultObject(result, false)
42 }
43
44 func (mo *mapObject) init() {
45 mo.baseObject.init()
46 mo.m = newOrderedMap(mo.val.runtime.getHash())
47 }
48
49 func (mo *mapObject) exportType() reflect.Type {
50 return mapExportType
51 }
52
53 func (mo *mapObject) export(ctx *objectExportCtx) interface{} {
54 m := make([][2]interface{}, mo.m.size)
55 ctx.put(mo.val, m)
56
57 iter := mo.m.newIter()
58 for i := 0; i < len(m); i++ {
59 entry := iter.next()
60 if entry == nil {
61 break
62 }
63 m[i][0] = exportValue(entry.key, ctx)
64 m[i][1] = exportValue(entry.value, ctx)
65 }
66
67 return m
68 }
69
70 func (mo *mapObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
71 dst.Set(reflect.MakeMap(typ))
72 ctx.putTyped(mo.val, typ, dst.Interface())
73 keyTyp := typ.Key()
74 elemTyp := typ.Elem()
75 iter := mo.m.newIter()
76 r := mo.val.runtime
77 for {
78 entry := iter.next()
79 if entry == nil {
80 break
81 }
82 keyVal := reflect.New(keyTyp).Elem()
83 err := r.toReflectValue(entry.key, keyVal, ctx)
84 if err != nil {
85 return err
86 }
87 elemVal := reflect.New(elemTyp).Elem()
88 err = r.toReflectValue(entry.value, elemVal, ctx)
89 if err != nil {
90 return err
91 }
92 dst.SetMapIndex(keyVal, elemVal)
93 }
94 return nil
95 }
96
97 func (r *Runtime) mapProto_clear(call FunctionCall) Value {
98 thisObj := r.toObject(call.This)
99 mo, ok := thisObj.self.(*mapObject)
100 if !ok {
101 panic(r.NewTypeError("Method Map.prototype.clear called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
102 }
103
104 mo.m.clear()
105
106 return _undefined
107 }
108
109 func (r *Runtime) mapProto_delete(call FunctionCall) Value {
110 thisObj := r.toObject(call.This)
111 mo, ok := thisObj.self.(*mapObject)
112 if !ok {
113 panic(r.NewTypeError("Method Map.prototype.delete called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
114 }
115
116 return r.toBoolean(mo.m.remove(call.Argument(0)))
117 }
118
119 func (r *Runtime) mapProto_get(call FunctionCall) Value {
120 thisObj := r.toObject(call.This)
121 mo, ok := thisObj.self.(*mapObject)
122 if !ok {
123 panic(r.NewTypeError("Method Map.prototype.get called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
124 }
125
126 return nilSafe(mo.m.get(call.Argument(0)))
127 }
128
129 func (r *Runtime) mapProto_has(call FunctionCall) Value {
130 thisObj := r.toObject(call.This)
131 mo, ok := thisObj.self.(*mapObject)
132 if !ok {
133 panic(r.NewTypeError("Method Map.prototype.has called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
134 }
135 if mo.m.has(call.Argument(0)) {
136 return valueTrue
137 }
138 return valueFalse
139 }
140
141 func (r *Runtime) mapProto_set(call FunctionCall) Value {
142 thisObj := r.toObject(call.This)
143 mo, ok := thisObj.self.(*mapObject)
144 if !ok {
145 panic(r.NewTypeError("Method Map.prototype.set called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
146 }
147 mo.m.set(call.Argument(0), call.Argument(1))
148 return call.This
149 }
150
151 func (r *Runtime) mapProto_entries(call FunctionCall) Value {
152 return r.createMapIterator(call.This, iterationKindKeyValue)
153 }
154
155 func (r *Runtime) mapProto_forEach(call FunctionCall) Value {
156 thisObj := r.toObject(call.This)
157 mo, ok := thisObj.self.(*mapObject)
158 if !ok {
159 panic(r.NewTypeError("Method Map.prototype.forEach called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
160 }
161 callbackFn, ok := r.toObject(call.Argument(0)).self.assertCallable()
162 if !ok {
163 panic(r.NewTypeError("object is not a function %s"))
164 }
165 t := call.Argument(1)
166 iter := mo.m.newIter()
167 for {
168 entry := iter.next()
169 if entry == nil {
170 break
171 }
172 callbackFn(FunctionCall{This: t, Arguments: []Value{entry.value, entry.key, thisObj}})
173 }
174
175 return _undefined
176 }
177
178 func (r *Runtime) mapProto_keys(call FunctionCall) Value {
179 return r.createMapIterator(call.This, iterationKindKey)
180 }
181
182 func (r *Runtime) mapProto_values(call FunctionCall) Value {
183 return r.createMapIterator(call.This, iterationKindValue)
184 }
185
186 func (r *Runtime) mapProto_getSize(call FunctionCall) Value {
187 thisObj := r.toObject(call.This)
188 mo, ok := thisObj.self.(*mapObject)
189 if !ok {
190 panic(r.NewTypeError("Method get Map.prototype.size called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
191 }
192 return intToValue(int64(mo.m.size))
193 }
194
195 func (r *Runtime) builtin_newMap(args []Value, newTarget *Object) *Object {
196 if newTarget == nil {
197 panic(r.needNew("Map"))
198 }
199 proto := r.getPrototypeFromCtor(newTarget, r.global.Map, r.global.MapPrototype)
200 o := &Object{runtime: r}
201
202 mo := &mapObject{}
203 mo.class = classObject
204 mo.val = o
205 mo.extensible = true
206 o.self = mo
207 mo.prototype = proto
208 mo.init()
209 if len(args) > 0 {
210 if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
211 adder := mo.getStr("set", nil)
212 adderFn := toMethod(adder)
213 if adderFn == nil {
214 panic(r.NewTypeError("Map.set in missing"))
215 }
216 iter := r.getIterator(arg, nil)
217 i0 := valueInt(0)
218 i1 := valueInt(1)
219 if adder == r.global.mapAdder {
220 iter.iterate(func(item Value) {
221 itemObj := r.toObject(item)
222 k := nilSafe(itemObj.self.getIdx(i0, nil))
223 v := nilSafe(itemObj.self.getIdx(i1, nil))
224 mo.m.set(k, v)
225 })
226 } else {
227 iter.iterate(func(item Value) {
228 itemObj := r.toObject(item)
229 k := itemObj.self.getIdx(i0, nil)
230 v := itemObj.self.getIdx(i1, nil)
231 adderFn(FunctionCall{This: o, Arguments: []Value{k, v}})
232 })
233 }
234 }
235 }
236 return o
237 }
238
239 func (r *Runtime) createMapIterator(mapValue Value, kind iterationKind) Value {
240 obj := r.toObject(mapValue)
241 mapObj, ok := obj.self.(*mapObject)
242 if !ok {
243 panic(r.NewTypeError("Object is not a Map"))
244 }
245
246 o := &Object{runtime: r}
247
248 mi := &mapIterObject{
249 iter: mapObj.m.newIter(),
250 kind: kind,
251 }
252 mi.class = classObject
253 mi.val = o
254 mi.extensible = true
255 o.self = mi
256 mi.prototype = r.getMapIteratorPrototype()
257 mi.init()
258
259 return o
260 }
261
262 func (r *Runtime) mapIterProto_next(call FunctionCall) Value {
263 thisObj := r.toObject(call.This)
264 if iter, ok := thisObj.self.(*mapIterObject); ok {
265 return iter.next()
266 }
267 panic(r.NewTypeError("Method Map Iterator.prototype.next called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
268 }
269
270 func (r *Runtime) createMapProto(val *Object) objectImpl {
271 o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)
272
273 o._putProp("constructor", r.getMap(), true, false, true)
274 o._putProp("clear", r.newNativeFunc(r.mapProto_clear, "clear", 0), true, false, true)
275 r.global.mapAdder = r.newNativeFunc(r.mapProto_set, "set", 2)
276 o._putProp("set", r.global.mapAdder, true, false, true)
277 o._putProp("delete", r.newNativeFunc(r.mapProto_delete, "delete", 1), true, false, true)
278 o._putProp("forEach", r.newNativeFunc(r.mapProto_forEach, "forEach", 1), true, false, true)
279 o._putProp("has", r.newNativeFunc(r.mapProto_has, "has", 1), true, false, true)
280 o._putProp("get", r.newNativeFunc(r.mapProto_get, "get", 1), true, false, true)
281 o.setOwnStr("size", &valueProperty{
282 getterFunc: r.newNativeFunc(r.mapProto_getSize, "get size", 0),
283 accessor: true,
284 writable: true,
285 configurable: true,
286 }, true)
287 o._putProp("keys", r.newNativeFunc(r.mapProto_keys, "keys", 0), true, false, true)
288 o._putProp("values", r.newNativeFunc(r.mapProto_values, "values", 0), true, false, true)
289
290 entriesFunc := r.newNativeFunc(r.mapProto_entries, "entries", 0)
291 o._putProp("entries", entriesFunc, true, false, true)
292 o._putSym(SymIterator, valueProp(entriesFunc, true, false, true))
293 o._putSym(SymToStringTag, valueProp(asciiString(classMap), false, false, true))
294
295 return o
296 }
297
298 func (r *Runtime) createMap(val *Object) objectImpl {
299 o := r.newNativeConstructOnly(val, r.builtin_newMap, r.getMapPrototype(), "Map", 0)
300 r.putSpeciesReturnThis(o)
301
302 return o
303 }
304
305 func (r *Runtime) createMapIterProto(val *Object) objectImpl {
306 o := newBaseObjectObj(val, r.getIteratorPrototype(), classObject)
307
308 o._putProp("next", r.newNativeFunc(r.mapIterProto_next, "next", 0), true, false, true)
309 o._putSym(SymToStringTag, valueProp(asciiString(classMapIterator), false, false, true))
310
311 return o
312 }
313
314 func (r *Runtime) getMapIteratorPrototype() *Object {
315 var o *Object
316 if o = r.global.MapIteratorPrototype; o == nil {
317 o = &Object{runtime: r}
318 r.global.MapIteratorPrototype = o
319 o.self = r.createMapIterProto(o)
320 }
321 return o
322 }
323
324 func (r *Runtime) getMapPrototype() *Object {
325 ret := r.global.MapPrototype
326 if ret == nil {
327 ret = &Object{runtime: r}
328 r.global.MapPrototype = ret
329 ret.self = r.createMapProto(ret)
330 }
331 return ret
332 }
333
334 func (r *Runtime) getMap() *Object {
335 ret := r.global.Map
336 if ret == nil {
337 ret = &Object{runtime: r}
338 r.global.Map = ret
339 ret.self = r.createMap(ret)
340 }
341 return ret
342 }
343
View as plain text