NumberConstructor.cs 6.1 KB

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