SymbolConstructor.cs 4.8 KB

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