builtin_number.go 4.2 KB

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