From 02f6719d44a0a70f0fddfa3228ca9225f06d766c Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 13 Dec 2011 10:42:05 -0800 Subject: [PATCH] strconv: include package and function name in error strings Fixes #2548. R=golang-dev, rsc CC=golang-dev https://golang.org/cl/5484062 --- src/pkg/exp/sql/convert_test.go | 4 ++-- src/pkg/strconv/atob.go | 2 +- src/pkg/strconv/atof.go | 10 ++++++---- src/pkg/strconv/atof_test.go | 2 +- src/pkg/strconv/atoi.go | 28 +++++++++++++++++++++------- src/pkg/strconv/atoi_test.go | 12 ++++++------ 6 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/pkg/exp/sql/convert_test.go b/src/pkg/exp/sql/convert_test.go index e40b08c710..bed09ffb29 100644 --- a/src/pkg/exp/sql/convert_test.go +++ b/src/pkg/exp/sql/convert_test.go @@ -55,10 +55,10 @@ var conversionTests = []conversionTest{ // Strings to integers {s: "255", d: &scanuint8, wantuint: 255}, - {s: "256", d: &scanuint8, wanterr: `converting string "256" to a uint8: parsing "256": value out of range`}, + {s: "256", d: &scanuint8, wanterr: `converting string "256" to a uint8: strconv.ParseUint: parsing "256": value out of range`}, {s: "256", d: &scanuint16, wantuint: 256}, {s: "-1", d: &scanint, wantint: -1}, - {s: "foo", d: &scanint, wanterr: `converting string "foo" to a int: parsing "foo": invalid syntax`}, + {s: "foo", d: &scanint, wanterr: `converting string "foo" to a int: strconv.ParseInt: parsing "foo": invalid syntax`}, // True bools {s: true, d: &scanbool, wantbool: true}, diff --git a/src/pkg/strconv/atob.go b/src/pkg/strconv/atob.go index 1508118d2a..d0cb097213 100644 --- a/src/pkg/strconv/atob.go +++ b/src/pkg/strconv/atob.go @@ -14,7 +14,7 @@ func ParseBool(str string) (value bool, err error) { case "0", "f", "F", "false", "FALSE", "False": return false, nil } - return false, &NumError{str, ErrSyntax} + return false, syntaxError("ParseBool", str) } // FormatBool returns "true" or "false" according to the value of b diff --git a/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go index 1642c18d74..8bda89088b 100644 --- a/src/pkg/strconv/atof.go +++ b/src/pkg/strconv/atof.go @@ -338,6 +338,8 @@ func (d *decimal) atof32() (f float32, ok bool) { return } +const fnParseFloat = "ParseFloat" + func atof32(s string) (f float32, err error) { if val, ok := special(s); ok { return float32(val), nil @@ -345,7 +347,7 @@ func atof32(s string) (f float32, err error) { var d decimal if !d.set(s) { - return 0, &NumError{s, ErrSyntax} + return 0, syntaxError(fnParseFloat, s) } if optimize { if f, ok := d.atof32(); ok { @@ -355,7 +357,7 @@ func atof32(s string) (f float32, err error) { b, ovf := d.floatBits(&float32info) f = math.Float32frombits(uint32(b)) if ovf { - err = &NumError{s, ErrRange} + err = rangeError(fnParseFloat, s) } return f, err } @@ -367,7 +369,7 @@ func atof64(s string) (f float64, err error) { var d decimal if !d.set(s) { - return 0, &NumError{s, ErrSyntax} + return 0, syntaxError(fnParseFloat, s) } if optimize { if f, ok := d.atof64(); ok { @@ -377,7 +379,7 @@ func atof64(s string) (f float64, err error) { b, ovf := d.floatBits(&float64info) f = math.Float64frombits(b) if ovf { - err = &NumError{s, ErrRange} + err = rangeError(fnParseFloat, s) } return f, err } diff --git a/src/pkg/strconv/atof_test.go b/src/pkg/strconv/atof_test.go index a9820d1bba..4d5ce1714f 100644 --- a/src/pkg/strconv/atof_test.go +++ b/src/pkg/strconv/atof_test.go @@ -119,7 +119,7 @@ func init() { for i := range atoftests { test := &atoftests[i] if test.err != nil { - test.err = &NumError{test.in, test.err} + test.err = &NumError{"ParseFloat", test.in, test.err} } } } diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go index b0e584e193..59ef264d17 100644 --- a/src/pkg/strconv/atoi.go +++ b/src/pkg/strconv/atoi.go @@ -14,11 +14,22 @@ var ErrSyntax = errors.New("invalid syntax") // A NumError records a failed conversion. type NumError struct { - Num string // the input - Err error // the reason the conversion failed (ErrRange, ErrSyntax) + Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat) + Num string // the input + Err error // the reason the conversion failed (ErrRange, ErrSyntax) } -func (e *NumError) Error() string { return `parsing "` + e.Num + `": ` + e.Err.Error() } +func (e *NumError) Error() string { + return "strconv." + e.Func + ": " + `parsing "` + e.Num + `": ` + e.Err.Error() +} + +func syntaxError(fn, str string) *NumError { + return &NumError{fn, str, ErrSyntax} +} + +func rangeError(fn, str string) *NumError { + return &NumError{fn, str, ErrRange} +} const intSize = 32 << uint(^uint(0)>>63) @@ -116,7 +127,7 @@ func ParseUint(s string, b int, bitSize int) (n uint64, err error) { return n, nil Error: - return n, &NumError{s0, err} + return n, &NumError{"ParseUint", s0, err} } // ParseInt interprets a string s in the given base (2 to 36) and @@ -134,13 +145,15 @@ Error: // to s cannot be represented by a signed integer of the // given size, err.Error = ErrRange. func ParseInt(s string, base int, bitSize int) (i int64, err error) { + const fnParseInt = "ParseInt" + if bitSize == 0 { bitSize = int(IntSize) } // Empty string bad. if len(s) == 0 { - return 0, &NumError{s, ErrSyntax} + return 0, syntaxError(fnParseInt, s) } // Pick off leading sign. @@ -157,15 +170,16 @@ func ParseInt(s string, base int, bitSize int) (i int64, err error) { var un uint64 un, err = ParseUint(s, base, bitSize) if err != nil && err.(*NumError).Err != ErrRange { + err.(*NumError).Func = fnParseInt err.(*NumError).Num = s0 return 0, err } cutoff := uint64(1 << uint(bitSize-1)) if !neg && un >= cutoff { - return int64(cutoff - 1), &NumError{s0, ErrRange} + return int64(cutoff - 1), rangeError(fnParseInt, s0) } if neg && un > cutoff { - return -int64(cutoff), &NumError{s0, ErrRange} + return -int64(cutoff), rangeError(fnParseInt, s0) } n := int64(un) if neg { diff --git a/src/pkg/strconv/atoi_test.go b/src/pkg/strconv/atoi_test.go index 2d06efed0d..d0e7b61dba 100644 --- a/src/pkg/strconv/atoi_test.go +++ b/src/pkg/strconv/atoi_test.go @@ -152,37 +152,37 @@ func init() { for i := range atoui64tests { test := &atoui64tests[i] if test.err != nil { - test.err = &NumError{test.in, test.err} + test.err = &NumError{"ParseUint", test.in, test.err} } } for i := range btoui64tests { test := &btoui64tests[i] if test.err != nil { - test.err = &NumError{test.in, test.err} + test.err = &NumError{"ParseUint", test.in, test.err} } } for i := range atoi64tests { test := &atoi64tests[i] if test.err != nil { - test.err = &NumError{test.in, test.err} + test.err = &NumError{"ParseInt", test.in, test.err} } } for i := range btoi64tests { test := &btoi64tests[i] if test.err != nil { - test.err = &NumError{test.in, test.err} + test.err = &NumError{"ParseInt", test.in, test.err} } } for i := range atoui32tests { test := &atoui32tests[i] if test.err != nil { - test.err = &NumError{test.in, test.err} + test.err = &NumError{"ParseUint", test.in, test.err} } } for i := range atoi32tests { test := &atoi32tests[i] if test.err != nil { - test.err = &NumError{test.in, test.err} + test.err = &NumError{"ParseInt", test.in, test.err} } } } -- 2.50.0