SymbolConstructor.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #pragma warning disable CA1859 // Use concrete types when possible for improved performance -- most of constructor methods return JsValue
  2. using Jint.Collections;
  3. using Jint.Native.Function;
  4. using Jint.Native.Object;
  5. using Jint.Runtime;
  6. using Jint.Runtime.Descriptors;
  7. using Jint.Runtime.Interop;
  8. namespace Jint.Native.Symbol;
  9. /// <summary>
  10. /// 19.4
  11. /// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-symbol-objects
  12. /// </summary>
  13. internal sealed class SymbolConstructor : Constructor
  14. {
  15. private static readonly JsString _functionName = new JsString("Symbol");
  16. internal SymbolConstructor(
  17. Engine engine,
  18. Realm realm,
  19. FunctionPrototype functionPrototype,
  20. ObjectPrototype objectPrototype)
  21. : base(engine, realm, _functionName)
  22. {
  23. _prototype = functionPrototype;
  24. PrototypeObject = new SymbolPrototype(engine, realm, this, objectPrototype);
  25. _length = new PropertyDescriptor(JsNumber.PositiveZero, PropertyFlag.Configurable);
  26. _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
  27. }
  28. public SymbolPrototype PrototypeObject { get; }
  29. protected override void Initialize()
  30. {
  31. const PropertyFlag lengthFlags = PropertyFlag.Configurable;
  32. const PropertyFlag propertyFlags = PropertyFlag.AllForbidden;
  33. var properties = new PropertyDictionary(15, checkExistingKeys: false)
  34. {
  35. ["for"] = new PropertyDescriptor(new ClrFunction(Engine, "for", For, 1, lengthFlags), PropertyFlag.Writable | PropertyFlag.Configurable),
  36. ["keyFor"] = new PropertyDescriptor(new ClrFunction(Engine, "keyFor", KeyFor, 1, lengthFlags), PropertyFlag.Writable | PropertyFlag.Configurable),
  37. ["hasInstance"] = new PropertyDescriptor(GlobalSymbolRegistry.HasInstance, propertyFlags),
  38. ["isConcatSpreadable"] = new PropertyDescriptor(GlobalSymbolRegistry.IsConcatSpreadable, propertyFlags),
  39. ["iterator"] = new PropertyDescriptor(GlobalSymbolRegistry.Iterator, propertyFlags),
  40. ["match"] = new PropertyDescriptor(GlobalSymbolRegistry.Match, propertyFlags),
  41. ["matchAll"] = new PropertyDescriptor(GlobalSymbolRegistry.MatchAll, propertyFlags),
  42. ["replace"] = new PropertyDescriptor(GlobalSymbolRegistry.Replace, propertyFlags),
  43. ["search"] = new PropertyDescriptor(GlobalSymbolRegistry.Search, propertyFlags),
  44. ["species"] = new PropertyDescriptor(GlobalSymbolRegistry.Species, propertyFlags),
  45. ["split"] = new PropertyDescriptor(GlobalSymbolRegistry.Split, propertyFlags),
  46. ["toPrimitive"] = new PropertyDescriptor(GlobalSymbolRegistry.ToPrimitive, propertyFlags),
  47. ["toStringTag"] = new PropertyDescriptor(GlobalSymbolRegistry.ToStringTag, propertyFlags),
  48. ["unscopables"] = new PropertyDescriptor(GlobalSymbolRegistry.Unscopables, propertyFlags),
  49. ["asyncIterator"] = new PropertyDescriptor(GlobalSymbolRegistry.AsyncIterator, propertyFlags)
  50. };
  51. SetProperties(properties);
  52. }
  53. /// <summary>
  54. /// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-symbol-description
  55. /// </summary>
  56. protected internal override JsValue Call(JsValue thisObject, JsCallArguments arguments)
  57. {
  58. var description = arguments.At(0);
  59. var descString = description.IsUndefined()
  60. ? Undefined
  61. : TypeConverter.ToJsString(description);
  62. var value = GlobalSymbolRegistry.CreateSymbol(descString);
  63. return value;
  64. }
  65. /// <summary>
  66. /// https://tc39.es/ecma262/#sec-symbol.for
  67. /// </summary>
  68. private JsValue For(JsValue thisObject, JsCallArguments arguments)
  69. {
  70. var stringKey = TypeConverter.ToJsString(arguments.At(0));
  71. // 2. ReturnIfAbrupt(stringKey).
  72. if (!_engine.GlobalSymbolRegistry.TryGetSymbol(stringKey, out var symbol))
  73. {
  74. symbol = GlobalSymbolRegistry.CreateSymbol(stringKey);
  75. _engine.GlobalSymbolRegistry.Add(symbol);
  76. }
  77. return symbol;
  78. }
  79. /// <summary>
  80. /// https://tc39.es/ecma262/#sec-symbol.keyfor
  81. /// </summary>
  82. private JsValue KeyFor(JsValue thisObject, JsCallArguments arguments)
  83. {
  84. var symbol = arguments.At(0) as JsSymbol;
  85. if (symbol is null)
  86. {
  87. ExceptionHelper.ThrowTypeError(_realm);
  88. }
  89. if (_engine.GlobalSymbolRegistry.TryGetSymbol(symbol._value, out var e))
  90. {
  91. return e._value;
  92. }
  93. return Undefined;
  94. }
  95. public override ObjectInstance Construct(JsCallArguments arguments, JsValue newTarget)
  96. {
  97. ExceptionHelper.ThrowTypeError(_realm, "Symbol is not a constructor");
  98. return null;
  99. }
  100. public SymbolInstance Construct(JsSymbol symbol)
  101. {
  102. return new SymbolInstance(Engine, PrototypeObject, symbol);
  103. }
  104. }