using System.Globalization;
using System.Numerics;
using System.Text;
using Jint.Collections;
using Jint.Native.Object;
using Jint.Native.Symbol;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Interop;
namespace Jint.Native.BigInt;
///
/// https://tc39.es/ecma262/#sec-properties-of-the-bigint-prototype-object
///
internal sealed class BigIntPrototype : Prototype
{
private readonly BigIntConstructor _constructor;
internal BigIntPrototype(
Engine engine,
BigIntConstructor constructor,
ObjectPrototype objectPrototype)
: base(engine, engine.Realm)
{
_prototype = objectPrototype;
_constructor = constructor;
}
protected override void Initialize()
{
var properties = new PropertyDictionary(4, checkExistingKeys: false)
{
["constructor"] = new(_constructor, true, false, true),
["toString"] = new(new ClrFunction(Engine, "toString", ToBigIntString, 0, PropertyFlag.Configurable), true, false, true),
["toLocaleString"] = new(new ClrFunction(Engine, "toLocaleString", ToLocaleString, 0, PropertyFlag.Configurable), true, false, true),
["valueOf"] = new(new ClrFunction(Engine, "valueOf", ValueOf, 0, PropertyFlag.Configurable), true, false, true),
};
SetProperties(properties);
var symbols = new SymbolDictionary(1)
{
[GlobalSymbolRegistry.ToStringTag] = new("BigInt", false, false, true)
};
SetSymbols(symbols);
}
///
/// https://tc39.es/ecma402/#sup-bigint.prototype.tolocalestring
///
private JsValue ToLocaleString(JsValue thisObject, JsValue[] arguments)
{
var locales = arguments.At(0);
var options = arguments.At(1);
var x = ThisBigIntValue(thisObject);
//var numberFormat = (NumberFormat) Construct(_realm.Intrinsics.NumberFormat, new[] { locales, options });
// numberFormat.FormatNumeric(x);
return x._value.ToString("R", CultureInfo.InvariantCulture);
}
///
/// https://tc39.es/ecma262/#sec-bigint.prototype.valueof
///
private JsValue ValueOf(JsValue thisObject, JsValue[] arguments)
{
if (thisObject is BigIntInstance ni)
{
return ni.BigIntData;
}
if (thisObject is JsBigInt)
{
return thisObject;
}
ExceptionHelper.ThrowTypeError(_realm);
return null;
}
///
/// https://tc39.es/ecma262/#sec-bigint.prototype.tostring
///
private JsValue ToBigIntString(JsValue thisObject, JsValue[] arguments)
{
var x = ThisBigIntValue(thisObject);
var radix = arguments.At(0);
var radixMV = radix.IsUndefined()
? 10
: (int) TypeConverter.ToIntegerOrInfinity(radix);
if (radixMV is < 2 or > 36)
{
ExceptionHelper.ThrowRangeError(_realm, "radix must be between 2 and 36");
}
var value = x._value;
if (value == BigInteger.Zero)
{
return JsString.NumberZeroString;
}
if (radixMV == 10)
{
return value.ToString("R", CultureInfo.InvariantCulture);
}
var negative = value < 0;
if (negative)
{
value = -value;
}
const string Digits = "0123456789abcdefghijklmnopqrstuvwxyz";
var sb = new ValueStringBuilder(stackalloc char[64]);
for (; value > 0; value /= radixMV)
{
var d = (int) (value % radixMV);
sb.Append(Digits[d]);
}
if (negative)
{
sb.Append('-');
}
sb.Reverse();
return sb.ToString();
}
///
/// https://tc39.es/ecma262/#thisbigintvalue
///
private JsBigInt ThisBigIntValue(JsValue value)
{
switch (value)
{
case JsBigInt bigInt:
return bigInt;
case BigIntInstance bigIntInstance:
return bigIntInstance.BigIntData;
default:
ExceptionHelper.ThrowTypeError(_realm);
return default;
}
}
}