BigIntPrototype.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. using System.Globalization;
  2. using System.Numerics;
  3. using System.Text;
  4. using Jint.Collections;
  5. using Jint.Native.Object;
  6. using Jint.Native.Symbol;
  7. using Jint.Runtime;
  8. using Jint.Runtime.Descriptors;
  9. using Jint.Runtime.Interop;
  10. namespace Jint.Native.BigInt;
  11. /// <summary>
  12. /// https://tc39.es/ecma262/#sec-properties-of-the-bigint-prototype-object
  13. /// </summary>
  14. internal sealed class BigIntPrototype : Prototype
  15. {
  16. private readonly BigIntConstructor _constructor;
  17. internal BigIntPrototype(
  18. Engine engine,
  19. BigIntConstructor constructor,
  20. ObjectPrototype objectPrototype)
  21. : base(engine, engine.Realm)
  22. {
  23. _prototype = objectPrototype;
  24. _constructor = constructor;
  25. }
  26. protected override void Initialize()
  27. {
  28. var properties = new PropertyDictionary(4, checkExistingKeys: false)
  29. {
  30. ["constructor"] = new(_constructor, true, false, true),
  31. ["toString"] = new(new ClrFunction(Engine, "toString", ToBigIntString, 0, PropertyFlag.Configurable), true, false, true),
  32. ["toLocaleString"] = new(new ClrFunction(Engine, "toLocaleString", ToLocaleString, 0, PropertyFlag.Configurable), true, false, true),
  33. ["valueOf"] = new(new ClrFunction(Engine, "valueOf", ValueOf, 0, PropertyFlag.Configurable), true, false, true),
  34. };
  35. SetProperties(properties);
  36. var symbols = new SymbolDictionary(1)
  37. {
  38. [GlobalSymbolRegistry.ToStringTag] = new("BigInt", false, false, true)
  39. };
  40. SetSymbols(symbols);
  41. }
  42. /// <summary>
  43. /// https://tc39.es/ecma402/#sup-bigint.prototype.tolocalestring
  44. /// </summary>
  45. private JsValue ToLocaleString(JsValue thisObject, JsValue[] arguments)
  46. {
  47. var locales = arguments.At(0);
  48. var options = arguments.At(1);
  49. var x = ThisBigIntValue(thisObject);
  50. //var numberFormat = (NumberFormat) Construct(_realm.Intrinsics.NumberFormat, new[] { locales, options });
  51. // numberFormat.FormatNumeric(x);
  52. return x._value.ToString("R", CultureInfo.InvariantCulture);
  53. }
  54. /// <summary>
  55. /// https://tc39.es/ecma262/#sec-bigint.prototype.valueof
  56. /// </summary>
  57. private JsValue ValueOf(JsValue thisObject, JsValue[] arguments)
  58. {
  59. if (thisObject is BigIntInstance ni)
  60. {
  61. return ni.BigIntData;
  62. }
  63. if (thisObject is JsBigInt)
  64. {
  65. return thisObject;
  66. }
  67. ExceptionHelper.ThrowTypeError(_realm);
  68. return null;
  69. }
  70. /// <summary>
  71. /// https://tc39.es/ecma262/#sec-bigint.prototype.tostring
  72. /// </summary>
  73. private JsValue ToBigIntString(JsValue thisObject, JsValue[] arguments)
  74. {
  75. var x = ThisBigIntValue(thisObject);
  76. var radix = arguments.At(0);
  77. var radixMV = radix.IsUndefined()
  78. ? 10
  79. : (int) TypeConverter.ToIntegerOrInfinity(radix);
  80. if (radixMV is < 2 or > 36)
  81. {
  82. ExceptionHelper.ThrowRangeError(_realm, "radix must be between 2 and 36");
  83. }
  84. var value = x._value;
  85. if (value == BigInteger.Zero)
  86. {
  87. return JsString.NumberZeroString;
  88. }
  89. if (radixMV == 10)
  90. {
  91. return value.ToString("R", CultureInfo.InvariantCulture);
  92. }
  93. var negative = value < 0;
  94. if (negative)
  95. {
  96. value = -value;
  97. }
  98. const string Digits = "0123456789abcdefghijklmnopqrstuvwxyz";
  99. var sb = new ValueStringBuilder(stackalloc char[64]);
  100. for (; value > 0; value /= radixMV)
  101. {
  102. var d = (int) (value % radixMV);
  103. sb.Append(Digits[d]);
  104. }
  105. if (negative)
  106. {
  107. sb.Append('-');
  108. }
  109. sb.Reverse();
  110. return sb.ToString();
  111. }
  112. /// <summary>
  113. /// https://tc39.es/ecma262/#thisbigintvalue
  114. /// </summary>
  115. private JsBigInt ThisBigIntValue(JsValue value)
  116. {
  117. switch (value)
  118. {
  119. case JsBigInt bigInt:
  120. return bigInt;
  121. case BigIntInstance bigIntInstance:
  122. return bigIntInstance.BigIntData;
  123. default:
  124. ExceptionHelper.ThrowTypeError(_realm);
  125. return default;
  126. }
  127. }
  128. }