using Jint.Collections; using Jint.Native.Function; using Jint.Native.Object; using Jint.Native.Symbol; using Jint.Runtime; using Jint.Runtime.Descriptors; using Jint.Runtime.Interop; namespace Jint.Native.Set { public sealed class SetConstructor : FunctionInstance, IConstructor { private static readonly JsString _functionName = new JsString("Set"); private SetConstructor(Engine engine) : base(engine, _functionName, FunctionThisMode.Global) { } public SetPrototype PrototypeObject { get; private set; } public static SetConstructor CreateSetConstructor(Engine engine) { var obj = new SetConstructor(engine) { _prototype = engine.Function.PrototypeObject }; // The value of the [[Prototype]] internal property of the Set constructor is the Function prototype object obj.PrototypeObject = SetPrototype.CreatePrototypeObject(engine, obj); obj._length = new PropertyDescriptor(0, PropertyFlag.Configurable); // The initial value of Set.prototype is the Set prototype object obj._prototypeDescriptor = new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden); return obj; } protected override void Initialize() { var symbols = new SymbolDictionary(1) { [GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunctionInstance(_engine, "get [Symbol.species]", Species, 0, PropertyFlag.Configurable), set: Undefined, PropertyFlag.Configurable) }; SetSymbols(symbols); } private static JsValue Species(JsValue thisObject, JsValue[] arguments) { return thisObject; } public override JsValue Call(JsValue thisObject, JsValue[] arguments) { ExceptionHelper.ThrowTypeError(_engine, "Constructor Set requires 'new'"); return null; } /// /// https://tc39.es/ecma262/#sec-set-iterable /// public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget) { if (newTarget.IsUndefined()) { ExceptionHelper.ThrowTypeError(_engine); } var set = OrdinaryCreateFromConstructor(newTarget, PrototypeObject, static (engine, _) => new SetInstance(engine)); if (arguments.Length > 0 && !arguments[0].IsNullOrUndefined()) { var adderValue = set.Get("add"); if (!(adderValue is ICallable adder)) { return ExceptionHelper.ThrowTypeError(_engine, "add must be callable"); } var iterable = arguments.At(0).GetIterator(_engine); try { var args = new JsValue[1]; do { if (!iterable.TryIteratorStep(out var next)) { return set; } next.TryGetValue(CommonProperties.Value, out var nextValue); args[0] = nextValue; adder.Call(set, args); } while (true); } catch { iterable.Close(CompletionType.Throw); throw; } } return set; } } }