BigIntConstructor.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. using System.Numerics;
  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.BigInt;
  9. /// <summary>
  10. /// https://tc39.es/ecma262/#sec-properties-of-the-bigint-constructor
  11. /// </summary>
  12. internal sealed class BigIntConstructor : Constructor
  13. {
  14. private static readonly JsString _functionName = new("BigInt");
  15. public BigIntConstructor(
  16. Engine engine,
  17. Realm realm,
  18. FunctionPrototype functionPrototype,
  19. ObjectPrototype objectPrototype)
  20. : base(engine, realm, _functionName)
  21. {
  22. _prototype = functionPrototype;
  23. PrototypeObject = new BigIntPrototype(engine, this, objectPrototype);
  24. _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
  25. _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
  26. }
  27. protected override void Initialize()
  28. {
  29. var properties = new PropertyDictionary(2, checkExistingKeys: false)
  30. {
  31. ["asIntN"] = new(new ClrFunctionInstance(Engine, "asIntN", AsIntN, 2, PropertyFlag.Configurable), true, false, true),
  32. ["asUintN"] = new(new ClrFunctionInstance(Engine, "asUintN", AsUintN, 2, PropertyFlag.Configurable), true, false, true),
  33. };
  34. SetProperties(properties);
  35. }
  36. /// <summary>
  37. /// https://tc39.es/ecma262/#sec-bigint.asintn
  38. /// </summary>
  39. private JsValue AsIntN(JsValue thisObj, JsValue[] arguments)
  40. {
  41. var bits = (int) TypeConverter.ToIndex(_realm, arguments.At(0));
  42. var bigint = arguments.At(1).ToBigInteger(_engine);
  43. var mod = TypeConverter.BigIntegerModulo(bigint, BigInteger.Pow(2, bits));
  44. if (bits > 0 && mod >= BigInteger.Pow(2, bits - 1))
  45. {
  46. return (mod - BigInteger.Pow(2, bits));
  47. }
  48. return mod;
  49. }
  50. /// <summary>
  51. /// https://tc39.es/ecma262/#sec-bigint.asuintn
  52. /// </summary>
  53. private JsValue AsUintN(JsValue thisObj, JsValue[] arguments)
  54. {
  55. var bits = (int) TypeConverter.ToIndex(_realm, arguments.At(0));
  56. var bigint = arguments.At(1).ToBigInteger(_engine);
  57. var result = TypeConverter.BigIntegerModulo(bigint, BigInteger.Pow(2, bits));
  58. return result;
  59. }
  60. protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
  61. {
  62. if (arguments.Length == 0)
  63. {
  64. return JsBigInt.Zero;
  65. }
  66. var prim = TypeConverter.ToPrimitive(arguments.At(0), Types.Number);
  67. if (prim.IsNumber())
  68. {
  69. return NumberToBigInt((JsNumber) prim);
  70. }
  71. return prim.ToBigInteger(_engine);
  72. }
  73. /// <summary>
  74. /// https://tc39.es/ecma262/#sec-numbertobigint
  75. /// </summary>
  76. private JsBigInt NumberToBigInt(JsNumber value)
  77. {
  78. if (TypeConverter.IsIntegralNumber(value._value))
  79. {
  80. return JsBigInt.Create((long) value._value);
  81. }
  82. ExceptionHelper.ThrowRangeError(_realm, "The number " + value + " cannot be converted to a BigInt because it is not an integer");
  83. return null;
  84. }
  85. /// <summary>
  86. /// https://tc39.es/ecma262/#sec-bigint-constructor-number-value
  87. /// </summary>
  88. public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
  89. {
  90. var value = arguments.Length > 0
  91. ? JsBigInt.Create(arguments[0].ToBigInteger(_engine))
  92. : JsBigInt.Zero;
  93. if (newTarget.IsUndefined())
  94. {
  95. return Construct(value);
  96. }
  97. var o = OrdinaryCreateFromConstructor(
  98. newTarget,
  99. static intrinsics => intrinsics.BigInt.PrototypeObject,
  100. static (engine, realm, state) => new BigIntInstance(engine, state!),
  101. value);
  102. return o;
  103. }
  104. public BigIntPrototype PrototypeObject { get; }
  105. public BigIntInstance Construct(JsBigInt value)
  106. {
  107. var instance = new BigIntInstance(Engine, value)
  108. {
  109. _prototype = PrototypeObject
  110. };
  111. return instance;
  112. }
  113. }