value_string.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package otto
  2. import (
  3. "fmt"
  4. "math"
  5. "regexp"
  6. "strconv"
  7. "unicode/utf16"
  8. )
  9. var matchLeading0Exponent = regexp.MustCompile(`([eE][\+\-])0+([1-9])`) // 1e-07 => 1e-7
  10. // FIXME
  11. // https://code.google.com/p/v8/source/browse/branches/bleeding_edge/src/conversions.cc?spec=svn18082&r=18082
  12. func floatToString(value float64, bitsize int) string {
  13. // TODO Fit to ECMA-262 9.8.1 specification
  14. if math.IsNaN(value) {
  15. return "NaN"
  16. } else if math.IsInf(value, 0) {
  17. if math.Signbit(value) {
  18. return "-Infinity"
  19. }
  20. return "Infinity"
  21. }
  22. exponent := math.Log10(math.Abs(value))
  23. if exponent >= 21 || exponent < -6 {
  24. return matchLeading0Exponent.ReplaceAllString(strconv.FormatFloat(value, 'g', -1, bitsize), "$1$2")
  25. }
  26. return strconv.FormatFloat(value, 'f', -1, bitsize)
  27. }
  28. func numberToStringRadix(value Value, radix int) string {
  29. float := value.float64()
  30. switch {
  31. case math.IsNaN(float):
  32. return "NaN"
  33. case math.IsInf(float, 1):
  34. return "Infinity"
  35. case math.IsInf(float, -1):
  36. return "-Infinity"
  37. case float == 0:
  38. return "0"
  39. }
  40. // FIXME This is very broken
  41. // Need to do proper radix conversion for floats, ...
  42. // This truncates large floats (so bad).
  43. return strconv.FormatInt(int64(float), radix)
  44. }
  45. func (v Value) string() string {
  46. if v.kind == valueString {
  47. switch value := v.value.(type) {
  48. case string:
  49. return value
  50. case []uint16:
  51. return string(utf16.Decode(value))
  52. }
  53. }
  54. if v.IsUndefined() {
  55. return "undefined"
  56. }
  57. if v.IsNull() {
  58. return "null"
  59. }
  60. switch value := v.value.(type) {
  61. case bool:
  62. return strconv.FormatBool(value)
  63. case int:
  64. return strconv.FormatInt(int64(value), 10)
  65. case int8:
  66. return strconv.FormatInt(int64(value), 10)
  67. case int16:
  68. return strconv.FormatInt(int64(value), 10)
  69. case int32:
  70. return strconv.FormatInt(int64(value), 10)
  71. case int64:
  72. return strconv.FormatInt(value, 10)
  73. case uint:
  74. return strconv.FormatUint(uint64(value), 10)
  75. case uint8:
  76. return strconv.FormatUint(uint64(value), 10)
  77. case uint16:
  78. return strconv.FormatUint(uint64(value), 10)
  79. case uint32:
  80. return strconv.FormatUint(uint64(value), 10)
  81. case uint64:
  82. return strconv.FormatUint(value, 10)
  83. case float32:
  84. if value == 0 {
  85. return "0" // Take care not to return -0
  86. }
  87. return floatToString(float64(value), 32)
  88. case float64:
  89. if value == 0 {
  90. return "0" // Take care not to return -0
  91. }
  92. return floatToString(value, 64)
  93. case []uint16:
  94. return string(utf16.Decode(value))
  95. case string:
  96. return value
  97. case *object:
  98. return value.DefaultValue(defaultValueHintString).string()
  99. }
  100. panic(fmt.Errorf("%v.string( %T)", v.value, v.value))
  101. }