123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- package otto
- import (
- "errors"
- "fmt"
- "math"
- "regexp"
- "strconv"
- "strings"
- )
- var stringToNumberParseInteger = regexp.MustCompile(`^(?:0[xX])`)
- func parseNumber(value string) float64 {
- value = strings.Trim(value, builtinStringTrimWhitespace)
- if value == "" {
- return 0
- }
- var parseFloat bool
- switch {
- case strings.ContainsRune(value, '.'):
- parseFloat = true
- case stringToNumberParseInteger.MatchString(value):
- parseFloat = false
- default:
- parseFloat = true
- }
- if parseFloat {
- number, err := strconv.ParseFloat(value, 64)
- if err != nil && !errors.Is(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 (v Value) float64() float64 {
- switch v.kind {
- case valueUndefined:
- return math.NaN()
- case valueNull:
- return 0
- }
- switch value := v.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)", v.value))
- }
- const (
- sqrt1_2 float64 = math.Sqrt2 / 2
- )
- const (
- maxUint32 = math.MaxUint32
- maxInt = int(^uint(0) >> 1)
- // int64.
- int64MaxInt8 int64 = math.MaxInt8
- int64MinInt8 int64 = math.MinInt8
- int64MaxInt16 int64 = math.MaxInt16
- int64MinInt16 int64 = math.MinInt16
- int64MaxInt32 int64 = math.MaxInt32
- int64MinInt32 int64 = math.MinInt32
- int64MaxUint8 int64 = math.MaxUint8
- int64MaxUint16 int64 = math.MaxUint16
- int64MaxUint32 int64 = math.MaxUint32
- // float64.
- floatMaxInt float64 = float64(int(^uint(0) >> 1))
- floatMinInt float64 = float64(-maxInt - 1)
- floatMaxUint float64 = float64(^uint(0))
- floatMaxUint64 float64 = math.MaxUint64
- floatMaxInt64 float64 = math.MaxInt64
- floatMinInt64 float64 = math.MinInt64
- )
- func toIntegerFloat(value Value) float64 {
- float := value.float64()
- switch {
- case math.IsInf(float, 0):
- return float
- case math.IsNaN(float):
- return 0
- case float > 0:
- return math.Floor(float)
- default:
- return math.Ceil(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 (v Value) number() _number {
- var num _number
- switch value := v.value.(type) {
- case int8:
- num.int64 = int64(value)
- return num
- case int16:
- num.int64 = int64(value)
- return num
- case uint8:
- num.int64 = int64(value)
- return num
- case uint16:
- num.int64 = int64(value)
- return num
- case uint32:
- num.int64 = int64(value)
- return num
- case int:
- num.int64 = int64(value)
- return num
- case int64:
- num.int64 = value
- return num
- }
- float := v.float64()
- if float == 0 {
- return num
- }
- num.kind = numberFloat
- num.float64 = float
- if math.IsNaN(float) {
- num.kind = numberNaN
- return num
- }
- if math.IsInf(float, 0) {
- num.kind = numberInfinity
- }
- if float >= floatMaxInt64 {
- num.int64 = math.MaxInt64
- return num
- }
- if float <= floatMinInt64 {
- num.int64 = math.MinInt64
- return num
- }
- var integer float64
- if float > 0 {
- integer = math.Floor(float)
- } else {
- integer = math.Ceil(float)
- }
- if float == integer {
- num.kind = numberInteger
- }
- num.int64 = int64(float)
- return num
- }
- // 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) || floatValue == 0 {
- return 0
- }
- // Convert to int64 before int32 to force correct wrapping.
- return int32(int64(floatValue))
- }
- 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) || floatValue == 0 {
- return 0
- }
- // Convert to int64 before uint32 to force correct wrapping.
- return uint32(int64(floatValue))
- }
- // ECMA 262 - 6.0 - 7.1.8.
- 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) || floatValue == 0 {
- return 0
- }
- // Convert to int64 before uint16 to force correct wrapping.
- return uint16(int64(floatValue))
- }
- // toIntSign returns sign of a number converted to -1, 0 ,1.
- func toIntSign(value Value) int {
- switch value := value.value.(type) {
- case int8:
- if value > 0 {
- return 1
- } else if value < 0 {
- return -1
- }
- return 0
- case int16:
- if value > 0 {
- return 1
- } else if value < 0 {
- return -1
- }
- return 0
- case int32:
- if value > 0 {
- return 1
- } else if value < 0 {
- return -1
- }
- return 0
- case uint8:
- if value > 0 {
- return 1
- }
- return 0
- case uint16:
- if value > 0 {
- return 1
- }
- return 0
- case uint32:
- if 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
- }
- }
|