ai_old/goja/builtin_set.go

347 lines
8.9 KiB
Go
Raw Normal View History

2024-09-20 16:50:35 +08:00
package goja
import (
"fmt"
"reflect"
)
var setExportType = reflectTypeArray
type setObject struct {
baseObject
m *orderedMap
}
type setIterObject struct {
baseObject
iter *orderedMapIter
kind iterationKind
}
func (o *setIterObject) next() Value {
if o.iter == nil {
return o.val.runtime.createIterResultObject(_undefined, true)
}
entry := o.iter.next()
if entry == nil {
o.iter = nil
return o.val.runtime.createIterResultObject(_undefined, true)
}
var result Value
switch o.kind {
case iterationKindValue:
result = entry.key
default:
result = o.val.runtime.newArrayValues([]Value{entry.key, entry.key})
}
return o.val.runtime.createIterResultObject(result, false)
}
func (so *setObject) init() {
so.baseObject.init()
so.m = newOrderedMap(so.val.runtime.getHash())
}
func (so *setObject) exportType() reflect.Type {
return setExportType
}
func (so *setObject) export(ctx *objectExportCtx) interface{} {
a := make([]interface{}, so.m.size)
ctx.put(so.val, a)
iter := so.m.newIter()
for i := 0; i < len(a); i++ {
entry := iter.next()
if entry == nil {
break
}
a[i] = exportValue(entry.key, ctx)
}
return a
}
func (so *setObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
l := so.m.size
if typ.Kind() == reflect.Array {
if dst.Len() != l {
return fmt.Errorf("cannot convert a Set into an array, lengths mismatch: have %d, need %d)", l, dst.Len())
}
} else {
dst.Set(reflect.MakeSlice(typ, l, l))
}
ctx.putTyped(so.val, typ, dst.Interface())
iter := so.m.newIter()
r := so.val.runtime
for i := 0; i < l; i++ {
entry := iter.next()
if entry == nil {
break
}
err := r.toReflectValue(entry.key, dst.Index(i), ctx)
if err != nil {
return err
}
}
return nil
}
func (so *setObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
dst.Set(reflect.MakeMap(typ))
keyTyp := typ.Key()
elemTyp := typ.Elem()
iter := so.m.newIter()
r := so.val.runtime
for {
entry := iter.next()
if entry == nil {
break
}
keyVal := reflect.New(keyTyp).Elem()
err := r.toReflectValue(entry.key, keyVal, ctx)
if err != nil {
return err
}
dst.SetMapIndex(keyVal, reflect.Zero(elemTyp))
}
return nil
}
func (r *Runtime) setProto_add(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method Set.prototype.add called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
so.m.set(call.Argument(0), nil)
return call.This
}
func (r *Runtime) setProto_clear(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method Set.prototype.clear called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
so.m.clear()
return _undefined
}
func (r *Runtime) setProto_delete(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method Set.prototype.delete called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
return r.toBoolean(so.m.remove(call.Argument(0)))
}
func (r *Runtime) setProto_entries(call FunctionCall) Value {
return r.createSetIterator(call.This, iterationKindKeyValue)
}
func (r *Runtime) setProto_forEach(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method Set.prototype.forEach called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
callbackFn, ok := r.toObject(call.Argument(0)).self.assertCallable()
if !ok {
panic(r.NewTypeError("object is not a function %s"))
}
t := call.Argument(1)
iter := so.m.newIter()
for {
entry := iter.next()
if entry == nil {
break
}
callbackFn(FunctionCall{This: t, Arguments: []Value{entry.key, entry.key, thisObj}})
}
return _undefined
}
func (r *Runtime) setProto_has(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method Set.prototype.has called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
return r.toBoolean(so.m.has(call.Argument(0)))
}
func (r *Runtime) setProto_getSize(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method get Set.prototype.size called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
return intToValue(int64(so.m.size))
}
func (r *Runtime) setProto_values(call FunctionCall) Value {
return r.createSetIterator(call.This, iterationKindValue)
}
func (r *Runtime) builtin_newSet(args []Value, newTarget *Object) *Object {
if newTarget == nil {
panic(r.needNew("Set"))
}
proto := r.getPrototypeFromCtor(newTarget, r.global.Set, r.global.SetPrototype)
o := &Object{runtime: r}
so := &setObject{}
so.class = classObject
so.val = o
so.extensible = true
o.self = so
so.prototype = proto
so.init()
if len(args) > 0 {
if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
adder := so.getStr("add", nil)
stdArr := r.checkStdArrayIter(arg)
if adder == r.global.setAdder {
if stdArr != nil {
for _, v := range stdArr.values {
so.m.set(v, nil)
}
} else {
r.getIterator(arg, nil).iterate(func(item Value) {
so.m.set(item, nil)
})
}
} else {
adderFn := toMethod(adder)
if adderFn == nil {
panic(r.NewTypeError("Set.add in missing"))
}
if stdArr != nil {
for _, item := range stdArr.values {
adderFn(FunctionCall{This: o, Arguments: []Value{item}})
}
} else {
r.getIterator(arg, nil).iterate(func(item Value) {
adderFn(FunctionCall{This: o, Arguments: []Value{item}})
})
}
}
}
}
return o
}
func (r *Runtime) createSetIterator(setValue Value, kind iterationKind) Value {
obj := r.toObject(setValue)
setObj, ok := obj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Object is not a Set"))
}
o := &Object{runtime: r}
si := &setIterObject{
iter: setObj.m.newIter(),
kind: kind,
}
si.class = classObject
si.val = o
si.extensible = true
o.self = si
si.prototype = r.getSetIteratorPrototype()
si.init()
return o
}
func (r *Runtime) setIterProto_next(call FunctionCall) Value {
thisObj := r.toObject(call.This)
if iter, ok := thisObj.self.(*setIterObject); ok {
return iter.next()
}
panic(r.NewTypeError("Method Set Iterator.prototype.next called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
func (r *Runtime) createSetProto(val *Object) objectImpl {
o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)
o._putProp("constructor", r.getSet(), true, false, true)
r.global.setAdder = r.newNativeFunc(r.setProto_add, "add", 1)
o._putProp("add", r.global.setAdder, true, false, true)
o._putProp("clear", r.newNativeFunc(r.setProto_clear, "clear", 0), true, false, true)
o._putProp("delete", r.newNativeFunc(r.setProto_delete, "delete", 1), true, false, true)
o._putProp("forEach", r.newNativeFunc(r.setProto_forEach, "forEach", 1), true, false, true)
o._putProp("has", r.newNativeFunc(r.setProto_has, "has", 1), true, false, true)
o.setOwnStr("size", &valueProperty{
getterFunc: r.newNativeFunc(r.setProto_getSize, "get size", 0),
accessor: true,
writable: true,
configurable: true,
}, true)
valuesFunc := r.newNativeFunc(r.setProto_values, "values", 0)
o._putProp("values", valuesFunc, true, false, true)
o._putProp("keys", valuesFunc, true, false, true)
o._putProp("entries", r.newNativeFunc(r.setProto_entries, "entries", 0), true, false, true)
o._putSym(SymIterator, valueProp(valuesFunc, true, false, true))
o._putSym(SymToStringTag, valueProp(asciiString(classSet), false, false, true))
return o
}
func (r *Runtime) createSet(val *Object) objectImpl {
o := r.newNativeConstructOnly(val, r.builtin_newSet, r.getSetPrototype(), "Set", 0)
r.putSpeciesReturnThis(o)
return o
}
func (r *Runtime) createSetIterProto(val *Object) objectImpl {
o := newBaseObjectObj(val, r.getIteratorPrototype(), classObject)
o._putProp("next", r.newNativeFunc(r.setIterProto_next, "next", 0), true, false, true)
o._putSym(SymToStringTag, valueProp(asciiString(classSetIterator), false, false, true))
return o
}
func (r *Runtime) getSetIteratorPrototype() *Object {
var o *Object
if o = r.global.SetIteratorPrototype; o == nil {
o = &Object{runtime: r}
r.global.SetIteratorPrototype = o
o.self = r.createSetIterProto(o)
}
return o
}
func (r *Runtime) getSetPrototype() *Object {
ret := r.global.SetPrototype
if ret == nil {
ret = &Object{runtime: r}
r.global.SetPrototype = ret
ret.self = r.createSetProto(ret)
}
return ret
}
func (r *Runtime) getSet() *Object {
ret := r.global.Set
if ret == nil {
ret = &Object{runtime: r}
r.global.Set = ret
ret.self = r.createSet(ret)
}
return ret
}