builtin_number.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package goja
  2. import (
  3. "math"
  4. "strconv"
  5. )
  6. func (r *Runtime) numberproto_valueOf(call FunctionCall) Value {
  7. this := call.This
  8. if !isNumber(this) {
  9. r.typeErrorResult(true, "Value is not a number")
  10. }
  11. if _, ok := this.assertInt(); ok {
  12. return this
  13. }
  14. if _, ok := this.assertFloat(); ok {
  15. return this
  16. }
  17. if obj, ok := this.(*Object); ok {
  18. if v, ok := obj.self.(*primitiveValueObject); ok {
  19. return v.pValue
  20. }
  21. }
  22. r.typeErrorResult(true, "Number.prototype.valueOf is not generic")
  23. return nil
  24. }
  25. func isNumber(v Value) bool {
  26. switch t := v.(type) {
  27. case valueFloat, valueInt:
  28. return true
  29. case *Object:
  30. switch t := t.self.(type) {
  31. case *primitiveValueObject:
  32. return isNumber(t.pValue)
  33. }
  34. }
  35. return false
  36. }
  37. func (r *Runtime) numberproto_toString(call FunctionCall) Value {
  38. if !isNumber(call.This) {
  39. r.typeErrorResult(true, "Value is not a number")
  40. }
  41. var radix int
  42. if arg := call.Argument(0); arg != _undefined {
  43. radix = int(arg.ToInteger())
  44. } else {
  45. radix = 10
  46. }
  47. if radix < 2 || radix > 36 {
  48. panic(r.newError(r.global.RangeError, "toString() radix argument must be between 2 and 36"))
  49. }
  50. num := call.This.ToFloat()
  51. if math.IsNaN(num) {
  52. return stringNaN
  53. }
  54. if math.IsInf(num, 1) {
  55. return stringInfinity
  56. }
  57. if math.IsInf(num, -1) {
  58. return stringNegInfinity
  59. }
  60. if radix == 10 {
  61. var fmt byte
  62. if math.Abs(num) >= 1e21 {
  63. fmt = 'e'
  64. } else {
  65. fmt = 'f'
  66. }
  67. return asciiString(strconv.FormatFloat(num, fmt, -1, 64))
  68. }
  69. return asciiString(dtobasestr(num, radix))
  70. }
  71. func (r *Runtime) numberproto_toFixed(call FunctionCall) Value {
  72. prec := call.Argument(0).ToInteger()
  73. if prec < 0 || prec > 20 {
  74. panic(r.newError(r.global.RangeError, "toFixed() precision must be between 0 and 20"))
  75. }
  76. num := call.This.ToFloat()
  77. if math.IsNaN(num) {
  78. return stringNaN
  79. }
  80. if math.Abs(num) >= 1e21 {
  81. return asciiString(strconv.FormatFloat(num, 'g', -1, 64))
  82. }
  83. return asciiString(strconv.FormatFloat(num, 'f', int(prec), 64))
  84. }
  85. func (r *Runtime) numberproto_toExponential(call FunctionCall) Value {
  86. prec := call.Argument(0).ToInteger()
  87. if prec < 0 || prec > 20 {
  88. panic(r.newError(r.global.RangeError, "toExponential() precision must be between 0 and 20"))
  89. }
  90. num := call.This.ToFloat()
  91. if math.IsNaN(num) {
  92. return stringNaN
  93. }
  94. if math.Abs(num) >= 1e21 {
  95. return asciiString(strconv.FormatFloat(num, 'g', -1, 64))
  96. }
  97. return asciiString(strconv.FormatFloat(num, 'e', int(prec), 64))
  98. }
  99. func (r *Runtime) numberproto_toPrecision(call FunctionCall) Value {
  100. prec := call.Argument(0).ToInteger()
  101. if prec < 0 || prec > 20 {
  102. panic(r.newError(r.global.RangeError, "toPrecision() precision must be between 0 and 20"))
  103. }
  104. num := call.This.ToFloat()
  105. if math.IsNaN(num) {
  106. return stringNaN
  107. }
  108. if math.Abs(num) >= 1e21 {
  109. return asciiString(strconv.FormatFloat(num, 'g', -1, 64))
  110. }
  111. return asciiString(strconv.FormatFloat(num, 'g', int(prec), 64))
  112. }
  113. func (r *Runtime) initNumber() {
  114. r.global.NumberPrototype = r.newPrimitiveObject(valueInt(0), r.global.ObjectPrototype, classNumber)
  115. o := r.global.NumberPrototype.self
  116. o._putProp("valueOf", r.newNativeFunc(r.numberproto_valueOf, nil, "valueOf", nil, 0), true, false, true)
  117. o._putProp("toString", r.newNativeFunc(r.numberproto_toString, nil, "toString", nil, 0), true, false, true)
  118. o._putProp("toLocaleString", r.newNativeFunc(r.numberproto_toString, nil, "toLocaleString", nil, 0), true, false, true)
  119. o._putProp("toFixed", r.newNativeFunc(r.numberproto_toFixed, nil, "toFixed", nil, 1), true, false, true)
  120. o._putProp("toExponential", r.newNativeFunc(r.numberproto_toExponential, nil, "toExponential", nil, 1), true, false, true)
  121. o._putProp("toPrecision", r.newNativeFunc(r.numberproto_toPrecision, nil, "toPrecision", nil, 1), true, false, true)
  122. r.global.Number = r.newNativeFunc(r.builtin_Number, r.builtin_newNumber, "Number", r.global.NumberPrototype, 1)
  123. o = r.global.Number.self
  124. o._putProp("MAX_VALUE", valueFloat(math.MaxFloat64), false, false, false)
  125. o._putProp("MIN_VALUE", valueFloat(math.SmallestNonzeroFloat64), false, false, false)
  126. o._putProp("NaN", _NaN, false, false, false)
  127. o._putProp("NEGATIVE_INFINITY", _negativeInf, false, false, false)
  128. o._putProp("POSITIVE_INFINITY", _positiveInf, false, false, false)
  129. o._putProp("EPSILON", _epsilon, false, false, false)
  130. r.addToGlobal("Number", r.global.Number)
  131. }