1package otto 2 3import ( 4 "fmt" 5 "math" 6 "regexp" 7 "strconv" 8 "strings" 9) 10 11var stringToNumberParseInteger = regexp.MustCompile(`^(?:0[xX])`) 12 13func parseNumber(value string) float64 { 14 value = strings.Trim(value, builtinString_trim_whitespace) 15 16 if value == "" { 17 return 0 18 } 19 20 parseFloat := false 21 if strings.IndexRune(value, '.') != -1 { 22 parseFloat = true 23 } else if stringToNumberParseInteger.MatchString(value) { 24 parseFloat = false 25 } else { 26 parseFloat = true 27 } 28 29 if parseFloat { 30 number, err := strconv.ParseFloat(value, 64) 31 if err != nil && err.(*strconv.NumError).Err != strconv.ErrRange { 32 return math.NaN() 33 } 34 return number 35 } 36 37 number, err := strconv.ParseInt(value, 0, 64) 38 if err != nil { 39 return math.NaN() 40 } 41 return float64(number) 42} 43 44func (value Value) float64() float64 { 45 switch value.kind { 46 case valueUndefined: 47 return math.NaN() 48 case valueNull: 49 return 0 50 } 51 switch value := value.value.(type) { 52 case bool: 53 if value { 54 return 1 55 } 56 return 0 57 case int: 58 return float64(value) 59 case int8: 60 return float64(value) 61 case int16: 62 return float64(value) 63 case int32: 64 return float64(value) 65 case int64: 66 return float64(value) 67 case uint: 68 return float64(value) 69 case uint8: 70 return float64(value) 71 case uint16: 72 return float64(value) 73 case uint32: 74 return float64(value) 75 case uint64: 76 return float64(value) 77 case float64: 78 return value 79 case string: 80 return parseNumber(value) 81 case *_object: 82 return value.DefaultValue(defaultValueHintNumber).float64() 83 } 84 panic(fmt.Errorf("toFloat(%T)", value.value)) 85} 86 87const ( 88 float_2_64 float64 = 18446744073709551616.0 89 float_2_63 float64 = 9223372036854775808.0 90 float_2_32 float64 = 4294967296.0 91 float_2_31 float64 = 2147483648.0 92 float_2_16 float64 = 65536.0 93 integer_2_32 int64 = 4294967296 94 integer_2_31 int64 = 2146483648 95 sqrt1_2 float64 = math.Sqrt2 / 2 96) 97 98const ( 99 maxInt8 = math.MaxInt8 100 minInt8 = math.MinInt8 101 maxInt16 = math.MaxInt16 102 minInt16 = math.MinInt16 103 maxInt32 = math.MaxInt32 104 minInt32 = math.MinInt32 105 maxInt64 = math.MaxInt64 106 minInt64 = math.MinInt64 107 maxUint8 = math.MaxUint8 108 maxUint16 = math.MaxUint16 109 maxUint32 = math.MaxUint32 110 maxUint64 = math.MaxUint64 111 maxUint = ^uint(0) 112 minUint = 0 113 maxInt = int(^uint(0) >> 1) 114 minInt = -maxInt - 1 115 116 // int64 117 int64_maxInt int64 = int64(maxInt) 118 int64_minInt int64 = int64(minInt) 119 int64_maxInt8 int64 = math.MaxInt8 120 int64_minInt8 int64 = math.MinInt8 121 int64_maxInt16 int64 = math.MaxInt16 122 int64_minInt16 int64 = math.MinInt16 123 int64_maxInt32 int64 = math.MaxInt32 124 int64_minInt32 int64 = math.MinInt32 125 int64_maxUint8 int64 = math.MaxUint8 126 int64_maxUint16 int64 = math.MaxUint16 127 int64_maxUint32 int64 = math.MaxUint32 128 129 // float64 130 float_maxInt float64 = float64(int(^uint(0) >> 1)) 131 float_minInt float64 = float64(int(-maxInt - 1)) 132 float_minUint float64 = float64(0) 133 float_maxUint float64 = float64(uint(^uint(0))) 134 float_minUint64 float64 = float64(0) 135 float_maxUint64 float64 = math.MaxUint64 136 float_maxInt64 float64 = math.MaxInt64 137 float_minInt64 float64 = math.MinInt64 138) 139 140func toIntegerFloat(value Value) float64 { 141 float := value.float64() 142 if math.IsInf(float, 0) { 143 } else if math.IsNaN(float) { 144 float = 0 145 } else if float > 0 { 146 float = math.Floor(float) 147 } else { 148 float = math.Ceil(float) 149 } 150 return float 151} 152 153type _numberKind int 154 155const ( 156 numberInteger _numberKind = iota // 3.0 => 3.0 157 numberFloat // 3.14159 => 3.0, 1+2**63 > 2**63-1 158 numberInfinity // Infinity => 2**63-1 159 numberNaN // NaN => 0 160) 161 162type _number struct { 163 kind _numberKind 164 int64 int64 165 float64 float64 166} 167 168// FIXME 169// http://www.goinggo.net/2013/08/gustavos-ieee-754-brain-teaser.html 170// http://bazaar.launchpad.net/~niemeyer/strepr/trunk/view/6/strepr.go#L160 171func (value Value) number() (number _number) { 172 switch value := value.value.(type) { 173 case int8: 174 number.int64 = int64(value) 175 return 176 case int16: 177 number.int64 = int64(value) 178 return 179 case uint8: 180 number.int64 = int64(value) 181 return 182 case uint16: 183 number.int64 = int64(value) 184 return 185 case uint32: 186 number.int64 = int64(value) 187 return 188 case int: 189 number.int64 = int64(value) 190 return 191 case int64: 192 number.int64 = value 193 return 194 } 195 196 float := value.float64() 197 if float == 0 { 198 return 199 } 200 201 number.kind = numberFloat 202 number.float64 = float 203 204 if math.IsNaN(float) { 205 number.kind = numberNaN 206 return 207 } 208 209 if math.IsInf(float, 0) { 210 number.kind = numberInfinity 211 } 212 213 if float >= float_maxInt64 { 214 number.int64 = math.MaxInt64 215 return 216 } 217 218 if float <= float_minInt64 { 219 number.int64 = math.MinInt64 220 return 221 } 222 223 integer := float64(0) 224 if float > 0 { 225 integer = math.Floor(float) 226 } else { 227 integer = math.Ceil(float) 228 } 229 230 if float == integer { 231 number.kind = numberInteger 232 } 233 number.int64 = int64(float) 234 return 235} 236 237// ECMA 262: 9.5 238func toInt32(value Value) int32 { 239 { 240 switch value := value.value.(type) { 241 case int8: 242 return int32(value) 243 case int16: 244 return int32(value) 245 case int32: 246 return value 247 } 248 } 249 floatValue := value.float64() 250 if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) { 251 return 0 252 } 253 if floatValue == 0 { // This will work for +0 & -0 254 return 0 255 } 256 remainder := math.Mod(floatValue, float_2_32) 257 if remainder > 0 { 258 remainder = math.Floor(remainder) 259 } else { 260 remainder = math.Ceil(remainder) + float_2_32 261 } 262 if remainder > float_2_31 { 263 return int32(remainder - float_2_32) 264 } 265 return int32(remainder) 266} 267 268func toUint32(value Value) uint32 { 269 { 270 switch value := value.value.(type) { 271 case int8: 272 return uint32(value) 273 case int16: 274 return uint32(value) 275 case uint8: 276 return uint32(value) 277 case uint16: 278 return uint32(value) 279 case uint32: 280 return value 281 } 282 } 283 floatValue := value.float64() 284 if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) { 285 return 0 286 } 287 if floatValue == 0 { 288 return 0 289 } 290 remainder := math.Mod(floatValue, float_2_32) 291 if remainder > 0 { 292 remainder = math.Floor(remainder) 293 } else { 294 remainder = math.Ceil(remainder) + float_2_32 295 } 296 return uint32(remainder) 297} 298 299func toUint16(value Value) uint16 { 300 { 301 switch value := value.value.(type) { 302 case int8: 303 return uint16(value) 304 case uint8: 305 return uint16(value) 306 case uint16: 307 return value 308 } 309 } 310 floatValue := value.float64() 311 if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) { 312 return 0 313 } 314 if floatValue == 0 { 315 return 0 316 } 317 remainder := math.Mod(floatValue, float_2_16) 318 if remainder > 0 { 319 remainder = math.Floor(remainder) 320 } else { 321 remainder = math.Ceil(remainder) + float_2_16 322 } 323 return uint16(remainder) 324} 325