aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/obscuren/otto/value_number.go
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/obscuren/otto/value_number.go')
-rw-r--r--Godeps/_workspace/src/github.com/obscuren/otto/value_number.go335
1 files changed, 335 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/obscuren/otto/value_number.go b/Godeps/_workspace/src/github.com/obscuren/otto/value_number.go
new file mode 100644
index 000000000..badb3a542
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/obscuren/otto/value_number.go
@@ -0,0 +1,335 @@
+package otto
+
+import (
+ "fmt"
+ "math"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var stringToNumberParseInteger = regexp.MustCompile(`^(?:0[xX])`)
+
+func stringToFloat(value string) float64 {
+ value = strings.TrimSpace(value)
+
+ 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 toNumber(value Value) Value {
+ if value._valueType == valueNumber {
+ return value
+ }
+ return Value{valueNumber, toFloat(value)}
+}
+
+func toFloat(value Value) float64 {
+ switch value._valueType {
+ 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 stringToFloat(value)
+ case *_object:
+ return toFloat(value.DefaultValue(defaultValueHintNumber))
+ }
+ panic(fmt.Errorf("toFloat(%T)", value.value))
+}
+
+const (
+ float_2_64 float64 = 18446744073709551616.0
+ float_2_63 float64 = 9223372036854775808.0
+ float_2_32 float64 = 4294967296.0
+ float_2_31 float64 = 2147483648.0
+ float_2_16 float64 = 65536.0
+ integer_2_32 int64 = 4294967296
+ integer_2_31 int64 = 2146483648
+ sqrt1_2 float64 = math.Sqrt2 / 2
+)
+
+const (
+ maxInt8 = math.MaxInt8
+ minInt8 = math.MinInt8
+ maxInt16 = math.MaxInt16
+ minInt16 = math.MinInt16
+ maxInt32 = math.MaxInt32
+ minInt32 = math.MinInt32
+ maxInt64 = math.MaxInt64
+ minInt64 = math.MinInt64
+ maxUint8 = math.MaxUint8
+ maxUint16 = math.MaxUint16
+ maxUint32 = math.MaxUint32
+ maxUint64 = math.MaxUint64
+ maxUint = ^uint(0)
+ minUint = 0
+ maxInt = int(^uint(0) >> 1)
+ minInt = -maxInt - 1
+
+ // int64
+ int64_maxInt int64 = int64(maxInt)
+ int64_minInt int64 = int64(minInt)
+ 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_minUint float64 = float64(0)
+ float_maxUint float64 = float64(uint(^uint(0)))
+ float_minUint64 float64 = float64(0)
+ float_maxUint64 float64 = math.MaxUint64
+ float_maxInt64 float64 = math.MaxInt64
+ float_minInt64 float64 = math.MinInt64
+)
+
+func toIntegerFloat(value Value) float64 {
+ float := value.toFloat()
+ 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 _integerKind int
+
+const (
+ integerValid _integerKind = iota // 3.0 => 3.0
+ integerFloat // 3.14159 => 3.0
+ integerInfinite // Infinity => 2**63-1
+ integerInvalid // NaN => 0
+)
+
+type _integer struct {
+ _integerKind
+ value int64
+}
+
+func (self _integer) valid() bool {
+ return self._integerKind == integerValid || self._integerKind == integerFloat
+}
+
+func (self _integer) exact() bool {
+ return self._integerKind == integerValid
+}
+
+func (self _integer) infinite() bool {
+ return self._integerKind == integerInfinite
+}
+
+func toInteger(value Value) (integer _integer) {
+ switch value := value.value.(type) {
+ case int8:
+ integer.value = int64(value)
+ return
+ case int16:
+ integer.value = int64(value)
+ return
+ case uint8:
+ integer.value = int64(value)
+ return
+ case uint16:
+ integer.value = int64(value)
+ return
+ case uint32:
+ integer.value = int64(value)
+ return
+ case int:
+ integer.value = int64(value)
+ return
+ case int64:
+ integer.value = value
+ return
+ }
+ {
+ value := value.toFloat()
+ if value == 0 {
+ return
+ }
+ if math.IsNaN(value) {
+ integer._integerKind = integerInvalid
+ return
+ }
+ if math.IsInf(value, 0) {
+ integer._integerKind = integerInfinite
+ }
+ if value >= float_maxInt64 {
+ integer.value = math.MaxInt64
+ return
+ }
+ if value <= float_minInt64 {
+ integer.value = math.MinInt64
+ return
+ }
+ {
+ value0 := value
+ value1 := float64(0)
+ if value0 > 0 {
+ value1 = math.Floor(value0)
+ } else {
+ value1 = math.Ceil(value0)
+ }
+
+ if value0 != value1 {
+ integer._integerKind = integerFloat
+ }
+ integer.value = int64(value1)
+ 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.toFloat()
+ 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.toFloat()
+ 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.toFloat()
+ 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)
+}