123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- package otto
- import (
- "fmt"
- "math"
- "regexp"
- "strconv"
- "strings"
- )
- var stringToNumberParseInteger = regexp.MustCompile(`^(?:0[xX])`)
- func parseNumber(value string) float64 {
- value = strings.Trim(value, builtinString_trim_whitespace)
- if value == "" {
- return 0
- }
- parseFloat := false
- if strings.IndexRune(value, '.') != -1 {
- parseFloat = true
- } else if stringToNumberParseInteger.MatchString(value) {
- parseFloat = false
- } else {
- parseFloat = true
- }
- if parseFloat {
- number, err := strconv.ParseFloat(value, 64)
- if err != nil && err.(*strconv.NumError).Err != strconv.ErrRange {
- return math.NaN()
- }
- return number
- }
- number, err := strconv.ParseInt(value, 0, 64)
- if err != nil {
- return math.NaN()
- }
- return float64(number)
- }
- func (value Value) float64() float64 {
- switch value.kind {
- case valueUndefined:
- return math.NaN()
- case valueNull:
- return 0
- }
- switch value := value.value.(type) {
- case bool:
- if value {
- return 1
- }
- return 0
- case int:
- return float64(value)
- case int8:
- return float64(value)
- case int16:
- return float64(value)
- case int32:
- return float64(value)
- case int64:
- return float64(value)
- case uint:
- return float64(value)
- case uint8:
- return float64(value)
- case uint16:
- return float64(value)
- case uint32:
- return float64(value)
- case uint64:
- return float64(value)
- case float64:
- return value
- case string:
- return parseNumber(value)
- case *_object:
- return value.DefaultValue(defaultValueHintNumber).float64()
- }
- panic(fmt.Errorf("toFloat(%T)", value.value))
- }
- const (
- float_2_32 float64 = 4294967296.0
- float_2_31 float64 = 2147483648.0
- float_2_16 float64 = 65536.0
- sqrt1_2 float64 = math.Sqrt2 / 2
- )
- const (
- maxUint32 = math.MaxUint32
- maxInt = int(^uint(0) >> 1)
- // int64
- int64_maxInt8 int64 = math.MaxInt8
- int64_minInt8 int64 = math.MinInt8
- int64_maxInt16 int64 = math.MaxInt16
- int64_minInt16 int64 = math.MinInt16
- int64_maxInt32 int64 = math.MaxInt32
- int64_minInt32 int64 = math.MinInt32
- int64_maxUint8 int64 = math.MaxUint8
- int64_maxUint16 int64 = math.MaxUint16
- int64_maxUint32 int64 = math.MaxUint32
- // float64
- float_maxInt float64 = float64(int(^uint(0) >> 1))
- float_minInt float64 = float64(int(-maxInt - 1))
- float_maxUint float64 = float64(uint(^uint(0)))
- float_maxUint64 float64 = math.MaxUint64
- float_maxInt64 float64 = math.MaxInt64
- float_minInt64 float64 = math.MinInt64
- )
- func toIntegerFloat(value Value) float64 {
- float := value.float64()
- if math.IsInf(float, 0) {
- } else if math.IsNaN(float) {
- float = 0
- } else if float > 0 {
- float = math.Floor(float)
- } else {
- float = math.Ceil(float)
- }
- return float
- }
- type _numberKind int
- const (
- numberInteger _numberKind = iota // 3.0 => 3.0
- numberFloat // 3.14159 => 3.0, 1+2**63 > 2**63-1
- numberInfinity // Infinity => 2**63-1
- numberNaN // NaN => 0
- )
- type _number struct {
- kind _numberKind
- int64 int64
- float64 float64
- }
- // FIXME
- // http://www.goinggo.net/2013/08/gustavos-ieee-754-brain-teaser.html
- // http://bazaar.launchpad.net/~niemeyer/strepr/trunk/view/6/strepr.go#L160
- func (value Value) number() (number _number) {
- switch value := value.value.(type) {
- case int8:
- number.int64 = int64(value)
- return
- case int16:
- number.int64 = int64(value)
- return
- case uint8:
- number.int64 = int64(value)
- return
- case uint16:
- number.int64 = int64(value)
- return
- case uint32:
- number.int64 = int64(value)
- return
- case int:
- number.int64 = int64(value)
- return
- case int64:
- number.int64 = value
- return
- }
- float := value.float64()
- if float == 0 {
- return
- }
- number.kind = numberFloat
- number.float64 = float
- if math.IsNaN(float) {
- number.kind = numberNaN
- return
- }
- if math.IsInf(float, 0) {
- number.kind = numberInfinity
- }
- if float >= float_maxInt64 {
- number.int64 = math.MaxInt64
- return
- }
- if float <= float_minInt64 {
- number.int64 = math.MinInt64
- return
- }
- var integer float64
- if float > 0 {
- integer = math.Floor(float)
- } else {
- integer = math.Ceil(float)
- }
- if float == integer {
- number.kind = numberInteger
- }
- number.int64 = int64(float)
- return
- }
- // ECMA 262: 9.5
- func toInt32(value Value) int32 {
- {
- switch value := value.value.(type) {
- case int8:
- return int32(value)
- case int16:
- return int32(value)
- case int32:
- return value
- }
- }
- floatValue := value.float64()
- if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) {
- return 0
- }
- if floatValue == 0 { // This will work for +0 & -0
- return 0
- }
- remainder := math.Mod(floatValue, float_2_32)
- if remainder > 0 {
- remainder = math.Floor(remainder)
- } else {
- remainder = math.Ceil(remainder) + float_2_32
- }
- if remainder > float_2_31 {
- return int32(remainder - float_2_32)
- }
- return int32(remainder)
- }
- func toUint32(value Value) uint32 {
- {
- switch value := value.value.(type) {
- case int8:
- return uint32(value)
- case int16:
- return uint32(value)
- case uint8:
- return uint32(value)
- case uint16:
- return uint32(value)
- case uint32:
- return value
- }
- }
- floatValue := value.float64()
- if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) {
- return 0
- }
- if floatValue == 0 {
- return 0
- }
- remainder := math.Mod(floatValue, float_2_32)
- if remainder > 0 {
- remainder = math.Floor(remainder)
- } else {
- remainder = math.Ceil(remainder) + float_2_32
- }
- return uint32(remainder)
- }
- func toUint16(value Value) uint16 {
- {
- switch value := value.value.(type) {
- case int8:
- return uint16(value)
- case uint8:
- return uint16(value)
- case uint16:
- return value
- }
- }
- floatValue := value.float64()
- if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) {
- return 0
- }
- if floatValue == 0 {
- return 0
- }
- remainder := math.Mod(floatValue, float_2_16)
- if remainder > 0 {
- remainder = math.Floor(remainder)
- } else {
- remainder = math.Ceil(remainder) + float_2_16
- }
- return uint16(remainder)
- }
- // toIntSign returns sign of a number converted to -1, 0 ,1
- func toIntSign(value Value) int {
- switch value := value.value.(type) {
- case int8:
- if int8(value) > 0 {
- return 1
- } else if int8(value) < 0 {
- return -1
- }
- return 0
- case int16:
- if int16(value) > 0 {
- return 1
- } else if int16(value) < 0 {
- return -1
- }
- return 0
- case int32:
- if int32(value) > 0 {
- return 1
- } else if int32(value) < 0 {
- return -1
- }
- return 0
- case uint8:
- if uint8(value) > 0 {
- return 1
- } else if uint8(value) < 0 {
- return -1
- }
- return 0
- case uint16:
- if uint16(value) > 0 {
- return 1
- } else if uint16(value) < 0 {
- return -1
- }
- return 0
- case uint32:
- if uint32(value) > 0 {
- return 1
- } else if uint32(value) < 0 {
- return -1
- }
- return 0
- }
- floatValue := value.float64()
- switch {
- case math.IsNaN(floatValue), math.IsInf(floatValue, 0):
- return 0
- case floatValue == 0:
- return 0
- case floatValue > 0:
- return 1
- default:
- return -1
- }
- }
|