#pragma warning disable CA1859 // Use concrete types when possible for improved performance -- most of constructor methods return JsValue using Jint.Collections; using Jint.Native.Function; using Jint.Native.Object; using Jint.Runtime; using Jint.Runtime.Descriptors; using Jint.Runtime.Interop; namespace Jint.Native.Symbol { /// /// 19.4 /// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-symbol-objects /// internal sealed class SymbolConstructor : Constructor { private static readonly JsString _functionName = new JsString("Symbol"); internal SymbolConstructor( Engine engine, Realm realm, FunctionPrototype functionPrototype, ObjectPrototype objectPrototype) : base(engine, realm, _functionName) { _prototype = functionPrototype; PrototypeObject = new SymbolPrototype(engine, realm, this, objectPrototype); _length = new PropertyDescriptor(JsNumber.PositiveZero, PropertyFlag.Configurable); _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden); } public SymbolPrototype PrototypeObject { get; } protected override void Initialize() { const PropertyFlag lengthFlags = PropertyFlag.Configurable; const PropertyFlag propertyFlags = PropertyFlag.AllForbidden; var properties = new PropertyDictionary(15, checkExistingKeys: false) { ["for"] = new PropertyDescriptor(new ClrFunction(Engine, "for", For, 1, lengthFlags), PropertyFlag.Writable | PropertyFlag.Configurable), ["keyFor"] = new PropertyDescriptor(new ClrFunction(Engine, "keyFor", KeyFor, 1, lengthFlags), PropertyFlag.Writable | PropertyFlag.Configurable), ["hasInstance"] = new PropertyDescriptor(GlobalSymbolRegistry.HasInstance, propertyFlags), ["isConcatSpreadable"] = new PropertyDescriptor(GlobalSymbolRegistry.IsConcatSpreadable, propertyFlags), ["iterator"] = new PropertyDescriptor(GlobalSymbolRegistry.Iterator, propertyFlags), ["match"] = new PropertyDescriptor(GlobalSymbolRegistry.Match, propertyFlags), ["matchAll"] = new PropertyDescriptor(GlobalSymbolRegistry.MatchAll, propertyFlags), ["replace"] = new PropertyDescriptor(GlobalSymbolRegistry.Replace, propertyFlags), ["search"] = new PropertyDescriptor(GlobalSymbolRegistry.Search, propertyFlags), ["species"] = new PropertyDescriptor(GlobalSymbolRegistry.Species, propertyFlags), ["split"] = new PropertyDescriptor(GlobalSymbolRegistry.Split, propertyFlags), ["toPrimitive"] = new PropertyDescriptor(GlobalSymbolRegistry.ToPrimitive, propertyFlags), ["toStringTag"] = new PropertyDescriptor(GlobalSymbolRegistry.ToStringTag, propertyFlags), ["unscopables"] = new PropertyDescriptor(GlobalSymbolRegistry.Unscopables, propertyFlags), ["asyncIterator"] = new PropertyDescriptor(GlobalSymbolRegistry.AsyncIterator, propertyFlags) }; SetProperties(properties); } /// /// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-symbol-description /// protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments) { var description = arguments.At(0); var descString = description.IsUndefined() ? Undefined : TypeConverter.ToJsString(description); var value = GlobalSymbolRegistry.CreateSymbol(descString); return value; } /// /// https://tc39.es/ecma262/#sec-symbol.for /// private JsValue For(JsValue thisObject, JsValue[] arguments) { var stringKey = TypeConverter.ToJsString(arguments.At(0)); // 2. ReturnIfAbrupt(stringKey). if (!_engine.GlobalSymbolRegistry.TryGetSymbol(stringKey, out var symbol)) { symbol = GlobalSymbolRegistry.CreateSymbol(stringKey); _engine.GlobalSymbolRegistry.Add(symbol); } return symbol; } /// /// https://tc39.es/ecma262/#sec-symbol.keyfor /// private JsValue KeyFor(JsValue thisObject, JsValue[] arguments) { var symbol = arguments.At(0) as JsSymbol; if (symbol is null) { ExceptionHelper.ThrowTypeError(_realm); } if (_engine.GlobalSymbolRegistry.TryGetSymbol(symbol._value, out var e)) { return e._value; } return Undefined; } public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget) { ExceptionHelper.ThrowTypeError(_realm, "Symbol is not a constructor"); return null; } public SymbolInstance Construct(JsSymbol symbol) { return new SymbolInstance(Engine, PrototypeObject, symbol); } } }