github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/builtin_set.go (about) 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.global.Set, true, false, true) 278 r.global.setAdder = r.newNativeFunc(r.setProto_add, nil, "add", nil, 1) 279 o._putProp("add", r.global.setAdder, true, false, true) 280 281 o._putProp("clear", r.newNativeFunc(r.setProto_clear, nil, "clear", nil, 0), true, false, true) 282 o._putProp("delete", r.newNativeFunc(r.setProto_delete, nil, "delete", nil, 1), true, false, true) 283 o._putProp("forEach", r.newNativeFunc(r.setProto_forEach, nil, "forEach", nil, 1), true, false, true) 284 o._putProp("has", r.newNativeFunc(r.setProto_has, nil, "has", nil, 1), true, false, true) 285 o.setOwnStr("size", &valueProperty{ 286 getterFunc: r.newNativeFunc(r.setProto_getSize, nil, "get size", nil, 0), 287 accessor: true, 288 writable: true, 289 configurable: true, 290 }, true) 291 292 valuesFunc := r.newNativeFunc(r.setProto_values, nil, "values", nil, 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, nil, "entries", nil, 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.global.SetPrototype, "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, nil, "next", nil, 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) initSet() { 329 r.global.SetPrototype = r.newLazyObject(r.createSetProto) 330 r.global.Set = r.newLazyObject(r.createSet) 331 332 r.addToGlobal("Set", r.global.Set) 333 }