NumberConstructor.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using Jint.Collections;
  2. using Jint.Native.Function;
  3. using Jint.Native.Global;
  4. using Jint.Native.Object;
  5. using Jint.Runtime;
  6. using Jint.Runtime.Descriptors;
  7. using Jint.Runtime.Interop;
  8. namespace Jint.Native.Number;
  9. /// <summary>
  10. /// https://tc39.es/ecma262/#sec-number-constructor
  11. /// </summary>
  12. internal sealed class NumberConstructor : Constructor
  13. {
  14. private static readonly JsString _functionName = new JsString("Number");
  15. private const long MinSafeInteger = -9007199254740991;
  16. internal const long MaxSafeInteger = 9007199254740991;
  17. public NumberConstructor(
  18. Engine engine,
  19. Realm realm,
  20. FunctionPrototype functionPrototype,
  21. ObjectPrototype objectPrototype)
  22. : base(engine, realm, _functionName)
  23. {
  24. _prototype = functionPrototype;
  25. PrototypeObject = new NumberPrototype(engine, realm, this, objectPrototype);
  26. _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
  27. _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
  28. }
  29. protected override void Initialize()
  30. {
  31. var properties = new PropertyDictionary(15, checkExistingKeys: false)
  32. {
  33. ["MAX_VALUE"] = new PropertyDescriptor(new PropertyDescriptor(double.MaxValue, PropertyFlag.AllForbidden)),
  34. ["MIN_VALUE"] = new PropertyDescriptor(new PropertyDescriptor(double.Epsilon, PropertyFlag.AllForbidden)),
  35. ["NaN"] = new PropertyDescriptor(new PropertyDescriptor(double.NaN, PropertyFlag.AllForbidden)),
  36. ["NEGATIVE_INFINITY"] = new PropertyDescriptor(new PropertyDescriptor(double.NegativeInfinity, PropertyFlag.AllForbidden)),
  37. ["POSITIVE_INFINITY"] = new PropertyDescriptor(new PropertyDescriptor(double.PositiveInfinity, PropertyFlag.AllForbidden)),
  38. ["EPSILON"] = new PropertyDescriptor(new PropertyDescriptor(JsNumber.JavaScriptEpsilon, PropertyFlag.AllForbidden)),
  39. ["MIN_SAFE_INTEGER"] = new PropertyDescriptor(new PropertyDescriptor(MinSafeInteger, PropertyFlag.AllForbidden)),
  40. ["MAX_SAFE_INTEGER"] = new PropertyDescriptor(new PropertyDescriptor(MaxSafeInteger, PropertyFlag.AllForbidden)),
  41. ["isFinite"] = new PropertyDescriptor(new ClrFunction(Engine, "isFinite", IsFinite, 1, PropertyFlag.Configurable), true, false, true),
  42. ["isInteger"] = new PropertyDescriptor(new ClrFunction(Engine, "isInteger", IsInteger, 1, PropertyFlag.Configurable), true, false, true),
  43. ["isNaN"] = new PropertyDescriptor(new ClrFunction(Engine, "isNaN", IsNaN, 1, PropertyFlag.Configurable), true, false, true),
  44. ["isSafeInteger"] = new PropertyDescriptor(new ClrFunction(Engine, "isSafeInteger", IsSafeInteger, 1, PropertyFlag.Configurable), true, false, true),
  45. ["parseFloat"] = new PropertyDescriptor(new ClrFunction(Engine, "parseFloat", GlobalObject.ParseFloat, 0, PropertyFlag.Configurable), true, false, true),
  46. ["parseInt"] = new PropertyDescriptor(new ClrFunction(Engine, "parseInt", GlobalObject.ParseInt, 0, PropertyFlag.Configurable), true, false, true)
  47. };
  48. SetProperties(properties);
  49. }
  50. private static JsValue IsFinite(JsValue thisObject, JsValue[] arguments)
  51. {
  52. if (!(arguments.At(0) is JsNumber num))
  53. {
  54. return false;
  55. }
  56. return double.IsInfinity(num._value) || double.IsNaN(num._value) ? JsBoolean.False : JsBoolean.True;
  57. }
  58. private static JsValue IsInteger(JsValue thisObject, JsValue[] arguments)
  59. {
  60. if (!(arguments.At(0) is JsNumber num))
  61. {
  62. return false;
  63. }
  64. if (double.IsInfinity(num._value) || double.IsNaN(num._value))
  65. {
  66. return JsBoolean.False;
  67. }
  68. var integer = TypeConverter.ToInteger(num);
  69. return integer == num._value;
  70. }
  71. private static JsValue IsNaN(JsValue thisObject, JsValue[] arguments)
  72. {
  73. if (!(arguments.At(0) is JsNumber num))
  74. {
  75. return false;
  76. }
  77. return double.IsNaN(num._value);
  78. }
  79. private static JsValue IsSafeInteger(JsValue thisObject, JsValue[] arguments)
  80. {
  81. if (!(arguments.At(0) is JsNumber num))
  82. {
  83. return false;
  84. }
  85. if (double.IsInfinity(num._value) || double.IsNaN(num._value))
  86. {
  87. return JsBoolean.False;
  88. }
  89. var integer = TypeConverter.ToInteger(num);
  90. if (integer != num._value)
  91. {
  92. return false;
  93. }
  94. return System.Math.Abs(integer) <= MaxSafeInteger;
  95. }
  96. protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
  97. {
  98. var n = ProcessFirstParameter(arguments);
  99. return n;
  100. }
  101. /// <summary>
  102. /// https://tc39.es/ecma262/#sec-number-constructor-number-value
  103. /// </summary>
  104. public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
  105. {
  106. var n = ProcessFirstParameter(arguments);
  107. if (newTarget.IsUndefined())
  108. {
  109. return Construct(n);
  110. }
  111. var o = OrdinaryCreateFromConstructor(
  112. newTarget,
  113. static intrinsics => intrinsics.Number.PrototypeObject,
  114. static (engine, realm, state) => new NumberInstance(engine, state!), n);
  115. return o;
  116. }
  117. private static JsNumber ProcessFirstParameter(JsValue[] arguments)
  118. {
  119. var n = JsNumber.PositiveZero;
  120. if (arguments.Length > 0)
  121. {
  122. var prim = TypeConverter.ToNumeric(arguments[0]);
  123. if (prim.IsBigInt())
  124. {
  125. n = JsNumber.Create((long) ((JsBigInt) prim)._value);
  126. }
  127. else
  128. {
  129. n = (JsNumber) prim;
  130. }
  131. }
  132. return n;
  133. }
  134. public NumberPrototype PrototypeObject { get; }
  135. public NumberInstance Construct(JsNumber value)
  136. {
  137. var instance = new NumberInstance(Engine, value)
  138. {
  139. _prototype = PrototypeObject
  140. };
  141. return instance;
  142. }
  143. }