瀏覽代碼

Add support for uint64 and 64-bit binary notation

Add decode tests for uint,uint64,int,int64,float32,float64

Unmarshal uint64, use math constants for precision boundaries

Remove uint case, let uint64 cover uint overflows

Handle int64 and uint64 with 0b... notation

Make test cases contain literal values, reference math constants
Jordan Liggitt 11 年之前
父節點
當前提交
1dd72ac392
共有 3 個文件被更改,包括 144 次插入6 次删除
  1. 18 4
      decode.go
  2. 108 0
      decode_test.go
  3. 18 2
      resolve.go

+ 18 - 4
decode.go

@@ -4,6 +4,7 @@ import (
 	"encoding"
 	"encoding"
 	"encoding/base64"
 	"encoding/base64"
 	"fmt"
 	"fmt"
+	"math"
 	"reflect"
 	"reflect"
 	"strconv"
 	"strconv"
 	"time"
 	"time"
@@ -389,8 +390,13 @@ func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
 				out.SetInt(resolved)
 				out.SetInt(resolved)
 				good = true
 				good = true
 			}
 			}
+		case uint64:
+			if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
+				out.SetInt(int64(resolved))
+				good = true
+			}
 		case float64:
 		case float64:
-			if resolved < 1<<63-1 && !out.OverflowInt(int64(resolved)) {
+			if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
 				out.SetInt(int64(resolved))
 				out.SetInt(int64(resolved))
 				good = true
 				good = true
 			}
 			}
@@ -406,17 +412,22 @@ func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 		switch resolved := resolved.(type) {
 		switch resolved := resolved.(type) {
 		case int:
 		case int:
-			if resolved >= 0 {
+			if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
 				out.SetUint(uint64(resolved))
 				out.SetUint(uint64(resolved))
 				good = true
 				good = true
 			}
 			}
 		case int64:
 		case int64:
-			if resolved >= 0 {
+			if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
+				out.SetUint(uint64(resolved))
+				good = true
+			}
+		case uint64:
+			if !out.OverflowUint(uint64(resolved)) {
 				out.SetUint(uint64(resolved))
 				out.SetUint(uint64(resolved))
 				good = true
 				good = true
 			}
 			}
 		case float64:
 		case float64:
-			if resolved < 1<<64-1 && !out.OverflowUint(uint64(resolved)) {
+			if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
 				out.SetUint(uint64(resolved))
 				out.SetUint(uint64(resolved))
 				good = true
 				good = true
 			}
 			}
@@ -435,6 +446,9 @@ func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
 		case int64:
 		case int64:
 			out.SetFloat(float64(resolved))
 			out.SetFloat(float64(resolved))
 			good = true
 			good = true
+		case uint64:
+			out.SetFloat(float64(resolved))
+			good = true
 		case float64:
 		case float64:
 			out.SetFloat(resolved)
 			out.SetFloat(resolved)
 			good = true
 			good = true

+ 108 - 0
decode_test.go

@@ -267,6 +267,114 @@ var unmarshalTests = []struct {
 		map[string]uint64{},
 		map[string]uint64{},
 	},
 	},
 
 
+	// int
+	{
+		"int_max: 2147483647", // math.MaxInt32
+		map[string]int{"int_max": 2147483647},
+	},
+	{
+		"int_min: -2147483648", // math.MinInt32
+		map[string]int{"int_min": -2147483648},
+	},
+	{
+		"int_overflow: 9223372036854775808", // math.MaxInt64 + 1
+		map[string]int{},
+	},
+
+	// int64
+	{
+		"int64_max: 9223372036854775807", // math.MaxInt64
+		map[string]int64{"int64_max": 9223372036854775807},
+	},
+	{
+		"int64_max_base2: 0b111111111111111111111111111111111111111111111111111111111111111", // math.MaxInt64
+		map[string]int64{"int64_max_base2": 9223372036854775807},
+	},
+	{
+		"int64_min: -9223372036854775808", // math.MinInt64
+		map[string]int64{"int64_min": -9223372036854775808},
+	},
+	{
+		"int64_neg_base2: -0b111111111111111111111111111111111111111111111111111111111111111", // -math.MaxInt64
+		map[string]int64{"int64_neg_base2": -9223372036854775807},
+	},
+	{
+		"int64_overflow: 9223372036854775808", // math.MaxInt64 + 1
+		map[string]int64{},
+	},
+
+	// uint
+	{
+		"uint_min: 0",
+		map[string]uint{"uint_min": 0},
+	},
+	{
+		"uint_max: 4294967295", // math.MaxUint32
+		map[string]uint{"uint_max": 4294967295},
+	},
+	{
+		"uint_underflow: -1",
+		map[string]uint{},
+	},
+
+	// uint64
+	{
+		"uint64_min: 0",
+		map[string]uint{"uint64_min": 0},
+	},
+	{
+		"uint64_max: 18446744073709551615", // math.MaxUint64
+		map[string]uint64{"uint64_max": 18446744073709551615},
+	},
+	{
+		"uint64_max_base2: 0b1111111111111111111111111111111111111111111111111111111111111111", // math.MaxUint64
+		map[string]uint64{"uint64_max_base2": 18446744073709551615},
+	},
+	{
+		"uint64_maxint64: 9223372036854775807", // math.MaxInt64
+		map[string]uint64{"uint64_maxint64": 9223372036854775807},
+	},
+	{
+		"uint64_underflow: -1",
+		map[string]uint64{},
+	},
+
+	// float32
+	{
+		"float32_max: 3.40282346638528859811704183484516925440e+38", // math.MaxFloat32
+		map[string]float32{"float32_max": 3.40282346638528859811704183484516925440e+38},
+	},
+	{
+		"float32_nonzero: 1.401298464324817070923729583289916131280e-45", // math.SmallestNonzeroFloat32
+		map[string]float32{"float32_nonzero": 1.401298464324817070923729583289916131280e-45},
+	},
+	{
+		"float32_maxuint64: 18446744073709551615", // math.MaxUint64
+		map[string]float32{"float32_maxuint64": 1.8446744e+19},
+	},
+	{
+		"float32_maxuint64+1: 18446744073709551616", // math.MaxUint64 + 1
+		map[string]float32{"float32_maxuint64+1": 1.8446744e+19},
+	},
+
+	// float64
+	{
+		"float64_max: 1.797693134862315708145274237317043567981e+308", // math.MaxFloat64
+		map[string]float64{"float64_max": 1.797693134862315708145274237317043567981e+308},
+	},
+	{
+		"float64_nonzero: 4.940656458412465441765687928682213723651e-324", // math.SmallestNonzeroFloat64
+		map[string]float64{"float64_nonzero": 4.940656458412465441765687928682213723651e-324},
+	},
+	{
+		"float64_maxuint64: 18446744073709551615", // math.MaxUint64
+		map[string]float64{"float64_maxuint64": 1.8446744073709552e+19},
+	},
+	{
+		"float64_maxuint64+1: 18446744073709551616", // math.MaxUint64 + 1
+		map[string]float64{"float64_maxuint64+1": 1.8446744073709552e+19},
+	},
+
 	// Overflow cases.
 	// Overflow cases.
 	{
 	{
 		"v: 4294967297",
 		"v: 4294967297",

+ 18 - 2
resolve.go

@@ -131,6 +131,10 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
 					return yaml_INT_TAG, intv
 					return yaml_INT_TAG, intv
 				}
 				}
 			}
 			}
+			uintv, err := strconv.ParseUint(plain, 0, 64)
+			if err == nil {
+				return yaml_INT_TAG, uintv
+			}
 			floatv, err := strconv.ParseFloat(plain, 64)
 			floatv, err := strconv.ParseFloat(plain, 64)
 			if err == nil {
 			if err == nil {
 				return yaml_FLOAT_TAG, floatv
 				return yaml_FLOAT_TAG, floatv
@@ -138,12 +142,24 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
 			if strings.HasPrefix(plain, "0b") {
 			if strings.HasPrefix(plain, "0b") {
 				intv, err := strconv.ParseInt(plain[2:], 2, 64)
 				intv, err := strconv.ParseInt(plain[2:], 2, 64)
 				if err == nil {
 				if err == nil {
-					return yaml_INT_TAG, int(intv)
+					if intv == int64(int(intv)) {
+						return yaml_INT_TAG, int(intv)
+					} else {
+						return yaml_INT_TAG, intv
+					}
+				}
+				uintv, err := strconv.ParseUint(plain[2:], 2, 64)
+				if err == nil {
+					return yaml_INT_TAG, uintv
 				}
 				}
 			} else if strings.HasPrefix(plain, "-0b") {
 			} else if strings.HasPrefix(plain, "-0b") {
 				intv, err := strconv.ParseInt(plain[3:], 2, 64)
 				intv, err := strconv.ParseInt(plain[3:], 2, 64)
 				if err == nil {
 				if err == nil {
-					return yaml_INT_TAG, -int(intv)
+					if intv == int64(int(intv)) {
+						return yaml_INT_TAG, -int(intv)
+					} else {
+						return yaml_INT_TAG, -intv
+					}
 				}
 				}
 			}
 			}
 			// XXX Handle timestamps here.
 			// XXX Handle timestamps here.