go.ketch.com/lib/goja@v0.0.1/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 = classSet 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 iter := r.getIterator(arg, nil) 213 if adder == r.global.setAdder { 214 iter.iterate(func(item Value) { 215 so.m.set(item, nil) 216 }) 217 } else { 218 adderFn := toMethod(adder) 219 if adderFn == nil { 220 panic(r.NewTypeError("Set.add in missing")) 221 } 222 iter.iterate(func(item Value) { 223 adderFn(FunctionCall{This: o, Arguments: []Value{item}}) 224 }) 225 } 226 } 227 } 228 return o 229 } 230 231 func (r *Runtime) createSetIterator(setValue Value, kind iterationKind) Value { 232 obj := r.toObject(setValue) 233 setObj, ok := obj.self.(*setObject) 234 if !ok { 235 panic(r.NewTypeError("Object is not a Set")) 236 } 237 238 o := &Object{runtime: r} 239 240 si := &setIterObject{ 241 iter: setObj.m.newIter(), 242 kind: kind, 243 } 244 si.class = classSetIterator 245 si.val = o 246 si.extensible = true 247 o.self = si 248 si.prototype = r.global.SetIteratorPrototype 249 si.init() 250 251 return o 252 } 253 254 func (r *Runtime) setIterProto_next(call FunctionCall) Value { 255 thisObj := r.toObject(call.This) 256 if iter, ok := thisObj.self.(*setIterObject); ok { 257 return iter.next() 258 } 259 panic(r.NewTypeError("Method Set Iterator.prototype.next called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj}))) 260 } 261 262 func (r *Runtime) createSetProto(val *Object) objectImpl { 263 o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject) 264 265 o._putProp("constructor", r.global.Set, true, false, true) 266 r.global.setAdder = r.newNativeFunc(r.setProto_add, nil, "add", nil, 1) 267 o._putProp("add", r.global.setAdder, true, false, true) 268 269 o._putProp("clear", r.newNativeFunc(r.setProto_clear, nil, "clear", nil, 0), true, false, true) 270 o._putProp("delete", r.newNativeFunc(r.setProto_delete, nil, "delete", nil, 1), true, false, true) 271 o._putProp("forEach", r.newNativeFunc(r.setProto_forEach, nil, "forEach", nil, 1), true, false, true) 272 o._putProp("has", r.newNativeFunc(r.setProto_has, nil, "has", nil, 1), true, false, true) 273 o.setOwnStr("size", &valueProperty{ 274 getterFunc: r.newNativeFunc(r.setProto_getSize, nil, "get size", nil, 0), 275 accessor: true, 276 writable: true, 277 configurable: true, 278 }, true) 279 280 valuesFunc := r.newNativeFunc(r.setProto_values, nil, "values", nil, 0) 281 o._putProp("values", valuesFunc, true, false, true) 282 o._putProp("keys", valuesFunc, true, false, true) 283 o._putProp("entries", r.newNativeFunc(r.setProto_entries, nil, "entries", nil, 0), true, false, true) 284 o._putSym(SymIterator, valueProp(valuesFunc, true, false, true)) 285 o._putSym(SymToStringTag, valueProp(asciiString(classSet), false, false, true)) 286 287 return o 288 } 289 290 func (r *Runtime) createSet(val *Object) objectImpl { 291 o := r.newNativeConstructOnly(val, r.builtin_newSet, r.global.SetPrototype, "Set", 0) 292 r.putSpeciesReturnThis(o) 293 294 return o 295 } 296 297 func (r *Runtime) createSetIterProto(val *Object) objectImpl { 298 o := newBaseObjectObj(val, r.global.IteratorPrototype, classObject) 299 300 o._putProp("next", r.newNativeFunc(r.setIterProto_next, nil, "next", nil, 0), true, false, true) 301 o._putSym(SymToStringTag, valueProp(asciiString(classSetIterator), false, false, true)) 302 303 return o 304 } 305 306 func (r *Runtime) initSet() { 307 r.global.SetIteratorPrototype = r.newLazyObject(r.createSetIterProto) 308 309 r.global.SetPrototype = r.newLazyObject(r.createSetProto) 310 r.global.Set = r.newLazyObject(r.createSet) 311 312 r.addToGlobal("Set", r.global.Set) 313 }