value_number.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. package otto
  2. import (
  3. "errors"
  4. "fmt"
  5. "math"
  6. "regexp"
  7. "strconv"
  8. "strings"
  9. )
  10. var stringToNumberParseInteger = regexp.MustCompile(`^(?:0[xX])`)
  11. func parseNumber(value string) float64 {
  12. value = strings.Trim(value, builtinStringTrimWhitespace)
  13. if value == "" {
  14. return 0
  15. }
  16. var parseFloat bool
  17. switch {
  18. case strings.ContainsRune(value, '.'):
  19. parseFloat = true
  20. case stringToNumberParseInteger.MatchString(value):
  21. parseFloat = false
  22. default:
  23. parseFloat = true
  24. }
  25. if parseFloat {
  26. number, err := strconv.ParseFloat(value, 64)
  27. if err != nil && !errors.Is(err, strconv.ErrRange) {
  28. return math.NaN()
  29. }
  30. return number
  31. }
  32. number, err := strconv.ParseInt(value, 0, 64)
  33. if err != nil {
  34. return math.NaN()
  35. }
  36. return float64(number)
  37. }
  38. func (v Value) float64() float64 {
  39. switch v.kind {
  40. case valueUndefined:
  41. return math.NaN()
  42. case valueNull:
  43. return 0
  44. }
  45. switch value := v.value.(type) {
  46. case bool:
  47. if value {
  48. return 1
  49. }
  50. return 0
  51. case int:
  52. return float64(value)
  53. case int8:
  54. return float64(value)
  55. case int16:
  56. return float64(value)
  57. case int32:
  58. return float64(value)
  59. case int64:
  60. return float64(value)
  61. case uint:
  62. return float64(value)
  63. case uint8:
  64. return float64(value)
  65. case uint16:
  66. return float64(value)
  67. case uint32:
  68. return float64(value)
  69. case uint64:
  70. return float64(value)
  71. case float64:
  72. return value
  73. case string:
  74. return parseNumber(value)
  75. case *object:
  76. return value.DefaultValue(defaultValueHintNumber).float64()
  77. }
  78. panic(fmt.Errorf("toFloat(%T)", v.value))
  79. }
  80. const (
  81. sqrt1_2 float64 = math.Sqrt2 / 2
  82. )
  83. const (
  84. maxUint32 = math.MaxUint32
  85. maxInt = int(^uint(0) >> 1)
  86. // int64.
  87. int64MaxInt8 int64 = math.MaxInt8
  88. int64MinInt8 int64 = math.MinInt8
  89. int64MaxInt16 int64 = math.MaxInt16
  90. int64MinInt16 int64 = math.MinInt16
  91. int64MaxInt32 int64 = math.MaxInt32
  92. int64MinInt32 int64 = math.MinInt32
  93. int64MaxUint8 int64 = math.MaxUint8
  94. int64MaxUint16 int64 = math.MaxUint16
  95. int64MaxUint32 int64 = math.MaxUint32
  96. // float64.
  97. floatMaxInt float64 = float64(int(^uint(0) >> 1))
  98. floatMinInt float64 = float64(-maxInt - 1)
  99. floatMaxUint float64 = float64(^uint(0))
  100. floatMaxUint64 float64 = math.MaxUint64
  101. floatMaxInt64 float64 = math.MaxInt64
  102. floatMinInt64 float64 = math.MinInt64
  103. )
  104. func toIntegerFloat(value Value) float64 {
  105. float := value.float64()
  106. switch {
  107. case math.IsInf(float, 0):
  108. return float
  109. case math.IsNaN(float):
  110. return 0
  111. case float > 0:
  112. return math.Floor(float)
  113. default:
  114. return math.Ceil(float)
  115. }
  116. }
  117. type numberKind int
  118. const (
  119. numberInteger numberKind = iota // 3.0 => 3.0
  120. numberFloat // 3.14159 => 3.0, 1+2**63 > 2**63-1
  121. numberInfinity // Infinity => 2**63-1
  122. numberNaN // NaN => 0
  123. )
  124. type _number struct {
  125. kind numberKind
  126. int64 int64
  127. float64 float64
  128. }
  129. // FIXME
  130. // http://www.goinggo.net/2013/08/gustavos-ieee-754-brain-teaser.html
  131. // http://bazaar.launchpad.net/~niemeyer/strepr/trunk/view/6/strepr.go#L160
  132. func (v Value) number() _number {
  133. var num _number
  134. switch value := v.value.(type) {
  135. case int8:
  136. num.int64 = int64(value)
  137. return num
  138. case int16:
  139. num.int64 = int64(value)
  140. return num
  141. case uint8:
  142. num.int64 = int64(value)
  143. return num
  144. case uint16:
  145. num.int64 = int64(value)
  146. return num
  147. case uint32:
  148. num.int64 = int64(value)
  149. return num
  150. case int:
  151. num.int64 = int64(value)
  152. return num
  153. case int64:
  154. num.int64 = value
  155. return num
  156. }
  157. float := v.float64()
  158. if float == 0 {
  159. return num
  160. }
  161. num.kind = numberFloat
  162. num.float64 = float
  163. if math.IsNaN(float) {
  164. num.kind = numberNaN
  165. return num
  166. }
  167. if math.IsInf(float, 0) {
  168. num.kind = numberInfinity
  169. }
  170. if float >= floatMaxInt64 {
  171. num.int64 = math.MaxInt64
  172. return num
  173. }
  174. if float <= floatMinInt64 {
  175. num.int64 = math.MinInt64
  176. return num
  177. }
  178. var integer float64
  179. if float > 0 {
  180. integer = math.Floor(float)
  181. } else {
  182. integer = math.Ceil(float)
  183. }
  184. if float == integer {
  185. num.kind = numberInteger
  186. }
  187. num.int64 = int64(float)
  188. return num
  189. }
  190. // ECMA 262: 9.5.
  191. func toInt32(value Value) int32 {
  192. switch value := value.value.(type) {
  193. case int8:
  194. return int32(value)
  195. case int16:
  196. return int32(value)
  197. case int32:
  198. return value
  199. }
  200. floatValue := value.float64()
  201. if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) || floatValue == 0 {
  202. return 0
  203. }
  204. // Convert to int64 before int32 to force correct wrapping.
  205. return int32(int64(floatValue))
  206. }
  207. func toUint32(value Value) uint32 {
  208. switch value := value.value.(type) {
  209. case int8:
  210. return uint32(value)
  211. case int16:
  212. return uint32(value)
  213. case uint8:
  214. return uint32(value)
  215. case uint16:
  216. return uint32(value)
  217. case uint32:
  218. return value
  219. }
  220. floatValue := value.float64()
  221. if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) || floatValue == 0 {
  222. return 0
  223. }
  224. // Convert to int64 before uint32 to force correct wrapping.
  225. return uint32(int64(floatValue))
  226. }
  227. // ECMA 262 - 6.0 - 7.1.8.
  228. func toUint16(value Value) uint16 {
  229. switch value := value.value.(type) {
  230. case int8:
  231. return uint16(value)
  232. case uint8:
  233. return uint16(value)
  234. case uint16:
  235. return value
  236. }
  237. floatValue := value.float64()
  238. if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) || floatValue == 0 {
  239. return 0
  240. }
  241. // Convert to int64 before uint16 to force correct wrapping.
  242. return uint16(int64(floatValue))
  243. }
  244. // toIntSign returns sign of a number converted to -1, 0 ,1.
  245. func toIntSign(value Value) int {
  246. switch value := value.value.(type) {
  247. case int8:
  248. if value > 0 {
  249. return 1
  250. } else if value < 0 {
  251. return -1
  252. }
  253. return 0
  254. case int16:
  255. if value > 0 {
  256. return 1
  257. } else if value < 0 {
  258. return -1
  259. }
  260. return 0
  261. case int32:
  262. if value > 0 {
  263. return 1
  264. } else if value < 0 {
  265. return -1
  266. }
  267. return 0
  268. case uint8:
  269. if value > 0 {
  270. return 1
  271. }
  272. return 0
  273. case uint16:
  274. if value > 0 {
  275. return 1
  276. }
  277. return 0
  278. case uint32:
  279. if value > 0 {
  280. return 1
  281. }
  282. return 0
  283. }
  284. floatValue := value.float64()
  285. switch {
  286. case math.IsNaN(floatValue), math.IsInf(floatValue, 0):
  287. return 0
  288. case floatValue == 0:
  289. return 0
  290. case floatValue > 0:
  291. return 1
  292. default:
  293. return -1
  294. }
  295. }