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  }