BigIntPrototype.cs 4.2 KB

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