value_string.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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. if math.IsNaN(float) {
  31. return "NaN"
  32. } else if math.IsInf(float, 1) {
  33. return "Infinity"
  34. } else if math.IsInf(float, -1) {
  35. return "-Infinity"
  36. }
  37. // FIXME This is very broken
  38. // Need to do proper radix conversion for floats, ...
  39. // This truncates large floats (so bad).
  40. return strconv.FormatInt(int64(float), radix)
  41. }
  42. func (value Value) string() string {
  43. if value.kind == valueString {
  44. switch value := value.value.(type) {
  45. case string:
  46. return value
  47. case []uint16:
  48. return string(utf16.Decode(value))
  49. }
  50. }
  51. if value.IsUndefined() {
  52. return "undefined"
  53. }
  54. if value.IsNull() {
  55. return "null"
  56. }
  57. switch value := value.value.(type) {
  58. case bool:
  59. return strconv.FormatBool(value)
  60. case int:
  61. return strconv.FormatInt(int64(value), 10)
  62. case int8:
  63. return strconv.FormatInt(int64(value), 10)
  64. case int16:
  65. return strconv.FormatInt(int64(value), 10)
  66. case int32:
  67. return strconv.FormatInt(int64(value), 10)
  68. case int64:
  69. return strconv.FormatInt(value, 10)
  70. case uint:
  71. return strconv.FormatUint(uint64(value), 10)
  72. case uint8:
  73. return strconv.FormatUint(uint64(value), 10)
  74. case uint16:
  75. return strconv.FormatUint(uint64(value), 10)
  76. case uint32:
  77. return strconv.FormatUint(uint64(value), 10)
  78. case uint64:
  79. return strconv.FormatUint(value, 10)
  80. case float32:
  81. if value == 0 {
  82. return "0" // Take care not to return -0
  83. }
  84. return floatToString(float64(value), 32)
  85. case float64:
  86. if value == 0 {
  87. return "0" // Take care not to return -0
  88. }
  89. return floatToString(value, 64)
  90. case []uint16:
  91. return string(utf16.Decode(value))
  92. case string:
  93. return value
  94. case *_object:
  95. return value.DefaultValue(defaultValueHintString).string()
  96. }
  97. panic(fmt.Errorf("%v.string( %T)", value.value, value.value))
  98. }