return *os.Error instead of bool from strconv.ato*
R=r
DELTA=137 (56 added, 4 deleted, 77 changed)
OCL=19505
CL=19522
diff --git a/src/lib/strconv/atof.go b/src/lib/strconv/atof.go
index c0bb1a6..5f019d3 100644
--- a/src/lib/strconv/atof.go
+++ b/src/lib/strconv/atof.go
@@ -10,7 +10,10 @@
package strconv
-import "strconv"
+import (
+ "os";
+ "strconv";
+)
// TODO(rsc): Better truncation handling.
func StringToDecimal(s string) (neg bool, d *Decimal, trunc bool, ok bool) {
@@ -314,43 +317,49 @@
// returns f, false, true, where f is the nearest floating point
// number rounded using IEEE754 unbiased rounding.
//
-// If s is not syntactically well-formed, returns ok == false.
+// If s is not syntactically well-formed, returns err = os.EINVAL.
//
// If s is syntactically well-formed but is more than 1/2 ULP
// away from the largest floating point number of the given size,
-// returns f = ±Inf, overflow = true, ok = true.
-export func atof64(s string) (f float64, overflow bool, ok bool) {
- neg, d, trunc, ok1 := StringToDecimal(s);
- if !ok1 {
- return 0, false, false;
+// returns f = ±Inf, err = os.ERANGE.
+export func atof64(s string) (f float64, err *os.Error) {
+ neg, d, trunc, ok := StringToDecimal(s);
+ if !ok {
+ return 0, os.EINVAL;
}
if f, ok := DecimalToFloat64(neg, d, trunc); ok {
- return f, false, true;
+ return f, nil;
}
- b, overflow1 := DecimalToFloatBits(neg, d, trunc, &float64info);
- return sys.float64frombits(b), overflow1, true;
+ b, ovf := DecimalToFloatBits(neg, d, trunc, &float64info);
+ f = sys.float64frombits(b);
+ if ovf {
+ err = os.ERANGE;
+ }
+ return f, err
}
-export func atof32(s string) (f float32, overflow bool, ok bool) {
- neg, d, trunc, ok1 := StringToDecimal(s);
- if !ok1 {
- return 0, false, false;
+export func atof32(s string) (f float32, err *os.Error) {
+ neg, d, trunc, ok := StringToDecimal(s);
+ if !ok {
+ return 0, os.EINVAL;
}
if f, ok := DecimalToFloat32(neg, d, trunc); ok {
- return f, false, true;
+ return f, nil;
}
- b, overflow1 := DecimalToFloatBits(neg, d, trunc, &float32info);
- return sys.float32frombits(uint32(b)), overflow1, true;
+ b, ovf := DecimalToFloatBits(neg, d, trunc, &float32info);
+ f = sys.float32frombits(uint32(b));
+ if ovf {
+ err = os.ERANGE;
+ }
+ return f, err
}
-export func atof(s string) (f float, overflow bool, ok bool) {
+export func atof(s string) (f float, err *os.Error) {
if floatsize == 32 {
- var f1 float32;
- f1, overflow, ok = atof32(s);
- return float(f1), overflow, ok;
+ f1, err1 := atof32(s);
+ return float(f1), err1;
}
- var f1 float64;
- f1, overflow, ok = atof64(s);
- return float(f1), overflow, ok;
+ f1, err1 := atof64(s);
+ return float(f1), err1;
}
diff --git a/src/lib/strconv/atoi.go b/src/lib/strconv/atoi.go
index 7f741c3..cd02df1 100644
--- a/src/lib/strconv/atoi.go
+++ b/src/lib/strconv/atoi.go
@@ -3,42 +3,59 @@
// license that can be found in the LICENSE file.
package strconv
+import "os"
+
+func IntSize() uint {
+ siz := uint(8);
+ for 1<<siz != 0 {
+ siz *= 2
+ }
+ return siz
+}
+var intsize = IntSize();
// Convert decimal string to unsigned integer.
-// TODO: Doesn't check for overflow.
-export func atoui64(s string) (i uint64, ok bool) {
+export func atoui64(s string) (i uint64, err *os.Error) {
// empty string bad
- if len(s) == 0 {
- return 0, false
+ if len(s) == 0 {
+ return 0, os.EINVAL
}
// pick off zero
if s == "0" {
- return 0, true
+ return 0, nil
}
-
- // otherwise, leading zero bad
+
+ // otherwise, leading zero bad:
+ // don't want to take something intended as octal.
if s[0] == '0' {
- return 0, false
+ return 0, os.EINVAL
}
// parse number
n := uint64(0);
for i := 0; i < len(s); i++ {
if s[i] < '0' || s[i] > '9' {
- return 0, false
+ return 0, os.EINVAL
}
- n = n*10 + uint64(s[i] - '0')
+ if n > (1<<64)/10 {
+ return 1<<64-1, os.ERANGE
+ }
+ n = n*10;
+ d := uint64(s[i] - '0');
+ if n+d < n {
+ return 1<<64-1, os.ERANGE
+ }
+ n += d;
}
- return n, true
+ return n, nil
}
// Convert decimal string to integer.
-// TODO: Doesn't check for overflow.
-export func atoi64(s string) (i int64, ok bool) {
+export func atoi64(s string) (i int64, err *os.Error) {
// empty string bad
if len(s) == 0 {
- return 0, false
+ return 0, os.EINVAL
}
// pick off leading sign
@@ -51,25 +68,49 @@
}
var un uint64;
- un, ok = atoui64(s);
- if !ok {
- return 0, false
+ un, err = atoui64(s);
+ if err != nil && err != os.ERANGE {
+ return 0, err
+ }
+ if !neg && un >= 1<<63 {
+ return 1<<63-1, os.ERANGE
+ }
+ if neg && un > 1<<63 {
+ return -1<<63, os.ERANGE
}
n := int64(un);
if neg {
n = -n
}
- return n, true
+ return n, nil
}
-export func atoui(s string) (i uint, ok bool) {
- ii, okok := atoui64(s);
- i = uint(ii);
- return i, okok
+export func atoui(s string) (i uint, err *os.Error) {
+ i1, e1 := atoui64(s);
+ if e1 != nil && e1 != os.ERANGE {
+ return 0, e1
+ }
+ i = uint(i1);
+ if uint64(i) != i1 {
+ // TODO: return uint(^0), os.ERANGE.
+ i1 = 1<<64-1;
+ return uint(i1), os.ERANGE
+ }
+ return i, nil
}
-export func atoi(s string) (i int, ok bool) {
- ii, okok := atoi64(s);
- i = int(ii);
- return i, okok
+export func atoi(s string) (i int, err *os.Error) {
+ i1, e1 := atoi64(s);
+ if e1 != nil && e1 != os.ERANGE {
+ return 0, e1
+ }
+ i = int(i1);
+ if int64(i) != i1 {
+ if i1 < 0 {
+ return -1<<(intsize-1), os.ERANGE
+ }
+ return 1<<(intsize-1) - 1, os.ERANGE
+ }
+ return i, nil
}
+
diff --git a/test/bugs/bug120.go b/test/bugs/bug120.go
index f4727bc..421f1db 100644
--- a/test/bugs/bug120.go
+++ b/test/bugs/bug120.go
@@ -43,8 +43,8 @@
v := strconv.ftoa64(t.f, 'g', -1);
if v != t.out {
println("Bad float64 const:", t.in, "want", t.out, "got", v);
- x, overflow, ok := strconv.atof64(t.out);
- if !ok {
+ x, err := strconv.atof64(t.out);
+ if err != nil {
panicln("bug120: strconv.atof64", t.out);
}
println("\twant exact:", strconv.ftoa64(x, 'g', 1000));
@@ -53,6 +53,6 @@
}
}
if !ok {
- panicln("bug120");
+ sys.exit(1);
}
}
diff --git a/test/chan/goroutines.go b/test/chan/goroutines.go
index b480e50..3fd80f2 100644
--- a/test/chan/goroutines.go
+++ b/test/chan/goroutines.go
@@ -10,6 +10,7 @@
package main
import (
+ "os";
"strconv";
)
@@ -20,9 +21,9 @@
func main() {
var n = 10000;
if sys.argc() > 1 {
- var ok bool;
- n, ok = strconv.atoi(sys.argv(1));
- if !ok {
+ var err *os.Error;
+ n, err = strconv.atoi(sys.argv(1));
+ if err != nil {
print("bad arg\n");
sys.exit(1);
}
diff --git a/test/golden.out b/test/golden.out
index efad874..2a870d6 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -125,7 +125,7 @@
=========== bugs/bug105.go
bugs/bug105.go:8: P: undefined
-bugs/bug105.go:9: illegal types for operand: RETURN
+bugs/bug105.go:8: illegal types for operand: RETURN
int
BUG: should compile
@@ -139,7 +139,7 @@
=========== bugs/bug117.go
bugs/bug117.go:9: undefined DOT get on PS
-bugs/bug117.go:10: illegal types for operand: RETURN
+bugs/bug117.go:9: illegal types for operand: RETURN
int
BUG: should compile
@@ -156,6 +156,7 @@
Bad float64 const: 1e23+1 want 1.0000000000000001e+23 got 1e+23
want exact: 100000000000000008388608
got exact: 99999999999999991611392
+BUG: bug120
=========== bugs/bug121.go
BUG: compilation succeeds incorrectly
diff --git a/test/stringslib.go b/test/stringslib.go
index d02890b..c44c139 100644
--- a/test/stringslib.go
+++ b/test/stringslib.go
@@ -35,7 +35,7 @@
func itoa(i int) string {
s := strconv.itoa(i);
- n, ok := strconv.atoi(s);
+ n, err := strconv.atoi(s);
if n != i {
print("itoa: ", i, " ", s, "\n");
panic("itoa")
@@ -92,20 +92,20 @@
a := split(faces, "");
if len(a) != 3 || a[0] != "☺" || a[1] != "☻" || a[2] != "☹" { panic("split faces empty") }
}
-
+
{
- n, ok := strconv.atoi("0"); if n != 0 || !ok { panic("atoi 0") }
- n, ok = strconv.atoi("-1"); if n != -1 || !ok { panic("atoi -1") }
- n, ok = strconv.atoi("+345"); if n != 345 || !ok { panic("atoi +345") }
- n, ok = strconv.atoi("9999"); if n != 9999 || !ok { panic("atoi 9999") }
- n, ok = strconv.atoi("20ba"); if n != 0 || ok { panic("atoi 20ba") }
- n, ok = strconv.atoi("hello"); if n != 0 || ok { panic("hello") }
+ n, err := strconv.atoi("0"); if n != 0 || err != nil { panic("atoi 0") }
+ n, err = strconv.atoi("-1"); if n != -1 || err != nil { panic("atoi -1") }
+ n, err = strconv.atoi("+345"); if n != 345 || err != nil { panic("atoi +345") }
+ n, err = strconv.atoi("9999"); if n != 9999 || err != nil { panic("atoi 9999") }
+ n, err = strconv.atoi("20ba"); if n != 0 || err == nil { panic("atoi 20ba") }
+ n, err = strconv.atoi("hello"); if n != 0 || err == nil { panic("hello") }
}
if strconv.ftoa(1e6, 'e', 6) != "1.000000e+06" { panic("ftoa 1e6") }
if strconv.ftoa(-1e-6, 'e', 6) != "-1.000000e-06" { panic("ftoa -1e-6") }
if strconv.ftoa(-1.234567e-6, 'e', 6) != "-1.234567e-06" { panic("ftoa -1.234567e-6") }
-
+
if itoa(0) != "0" { panic("itoa 0") }
if itoa(12345) != "12345" { panic("itoa 12345") }
if itoa(-1<<31) != "-2147483648" { panic("itoa 1<<31") }
@@ -114,7 +114,7 @@
// if itoa(-1<<63) != "-9223372036854775808" { panic("itoa 1<<63") }
{
- a, overflow, ok := strconv.atof64("-1.2345e4");
- if !ok || a != -12345. { panic(a, "atof64 -1.2345e4") }
+ a, err := strconv.atof64("-1.2345e4");
+ if err != nil || a != -12345. { panic(a, "atof64 -1.2345e4") }
}
}