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