BigIntConstructor.cs 4.1 KB

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