diff options
Diffstat (limited to 'src/pkg/fmt')
-rw-r--r-- | src/pkg/fmt/doc.go | 29 | ||||
-rw-r--r-- | src/pkg/fmt/fmt_test.go | 196 | ||||
-rw-r--r-- | src/pkg/fmt/format.go | 105 | ||||
-rw-r--r-- | src/pkg/fmt/print.go | 417 | ||||
-rw-r--r-- | src/pkg/fmt/scan.go | 208 | ||||
-rw-r--r-- | src/pkg/fmt/scan_test.go | 77 |
6 files changed, 590 insertions, 442 deletions
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go index 35a11e19f..7d4178da7 100644 --- a/src/pkg/fmt/doc.go +++ b/src/pkg/fmt/doc.go @@ -30,8 +30,9 @@ %X base 16, with upper-case letters for A-F %U Unicode format: U+1234; same as "U+%04X" Floating-point and complex constituents: - %b decimalless scientific notation with exponent a power - of two, in the manner of strconv.Ftoa32, e.g. -123456p-78 + %b decimalless scientific notation with exponent a power of two, + in the manner of strconv.FormatFloat with the 'b' format, + e.g. -123456p-78 %e scientific notation, e.g. -1234.456e+78 %E scientific notation, e.g. -1234.456E+78 %f decimal point but no exponent, e.g. 123.456 @@ -89,14 +90,22 @@ If an operand implements interface Formatter, that interface can be used for fine control of formatting. - If an operand implements method String() string that method + If the format (which is implicitly %v for Println etc.) is valid + for a string (%s %q %v %x %X), the following two rules also apply: + + 1. If an operand implements the error interface, the Error method + will be used to convert the object to a string, which will then + be formatted as required by the verb (if any). + + 2. If an operand implements method String() string, that method will be used to convert the object to a string, which will then - be formatted as required by the verb (if any). To avoid - recursion in cases such as - type X int - func (x X) String() string { return Sprintf("%d", x) } - cast the value before recurring: - func (x X) String() string { return Sprintf("%d", int(x)) } + be formatted as required by the verb (if any). + + To avoid recursion in cases such as + type X string + func (x X) String() string { return Sprintf("<%s>", x) } + convert the value before recurring: + func (x X) String() string { return Sprintf("<%s>", string(x)) } Format errors: @@ -122,7 +131,7 @@ An analogous set of functions scans formatted text to yield values. Scan, Scanf and Scanln read from os.Stdin; Fscan, - Fscanf and Fscanln read from a specified os.Reader; Sscan, + Fscanf and Fscanln read from a specified io.Reader; Sscan, Sscanf and Sscanln read from an argument string. Scanln, Fscanln and Sscanln stop scanning at a newline and require that the items be followed by one; Sscanf, Fscanf and Sscanf require diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go index b1ad34518..2f92f947c 100644 --- a/src/pkg/fmt/fmt_test.go +++ b/src/pkg/fmt/fmt_test.go @@ -12,6 +12,7 @@ import ( "runtime" // for the malloc count test only "strings" "testing" + "time" ) type ( @@ -47,8 +48,10 @@ func TestFmtInterface(t *testing.T) { const b32 uint32 = 1<<32 - 1 const b64 uint64 = 1<<64 - 1 -var array = []int{1, 2, 3, 4, 5} -var iarray = []interface{}{1, "hello", 2.5, nil} +var array = [5]int{1, 2, 3, 4, 5} +var iarray = [4]interface{}{1, "hello", 2.5, nil} +var slice = array[:] +var islice = iarray[:] type A struct { i int @@ -62,7 +65,7 @@ type I int func (i I) String() string { return Sprintf("<%d>", int(i)) } type B struct { - i I + I I j int } @@ -73,7 +76,7 @@ type C struct { type F int -func (f F) Format(s State, c int) { +func (f F) Format(s State, c rune) { Fprintf(s, "<%c=F(%d)>", c, int(f)) } @@ -84,8 +87,12 @@ func (g G) GoString() string { } type S struct { - f F // a struct field that Formats - g G // a struct field that GoStrings + F F // a struct field that Formats + G G // a struct field that GoStrings +} + +type SI struct { + I interface{} } // A type with a String method with pointer receiver for testing %p @@ -323,6 +330,12 @@ var fmttests = []struct { {"%v", &array, "&[1 2 3 4 5]"}, {"%v", &iarray, "&[1 hello 2.5 <nil>]"}, + // slices + {"%v", slice, "[1 2 3 4 5]"}, + {"%v", islice, "[1 hello 2.5 <nil>]"}, + {"%v", &slice, "&[1 2 3 4 5]"}, + {"%v", &islice, "&[1 hello 2.5 <nil>]"}, + // complexes with %v {"%v", 1 + 2i, "(1+2i)"}, {"%v", complex64(1 + 2i), "(1+2i)"}, @@ -333,14 +346,14 @@ var fmttests = []struct { {"%+v", A{1, 2, "a", []int{1, 2}}, `{i:1 j:2 s:a x:[1 2]}`}, // +v on structs with Stringable items - {"%+v", B{1, 2}, `{i:<1> j:2}`}, - {"%+v", C{1, B{2, 3}}, `{i:1 B:{i:<2> j:3}}`}, + {"%+v", B{1, 2}, `{I:<1> j:2}`}, + {"%+v", C{1, B{2, 3}}, `{i:1 B:{I:<2> j:3}}`}, // q on Stringable items {"%s", I(23), `<23>`}, {"%q", I(23), `"<23>"`}, {"%x", I(23), `3c32333e`}, - {"%d", I(23), `%!d(string=<23>)`}, + {"%d", I(23), `23`}, // Stringer applies only to string formats. // go syntax {"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`}, @@ -349,9 +362,18 @@ var fmttests = []struct { {"%#v", make(chan int), "(chan int)(0xPTR)"}, {"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"}, {"%#v", 1000000000, "1000000000"}, - {"%#v", map[string]int{"a": 1, "b": 2}, `map[string] int{"a":1, "b":2}`}, - {"%#v", map[string]B{"a": {1, 2}, "b": {3, 4}}, `map[string] fmt_test.B{"a":fmt_test.B{i:1, j:2}, "b":fmt_test.B{i:3, j:4}}`}, + {"%#v", map[string]int{"a": 1}, `map[string]int{"a":1}`}, + {"%#v", map[string]B{"a": {1, 2}}, `map[string]fmt_test.B{"a":fmt_test.B{I:1, j:2}}`}, {"%#v", []string{"a", "b"}, `[]string{"a", "b"}`}, + {"%#v", SI{}, `fmt_test.SI{I:interface {}(nil)}`}, + {"%#v", []int(nil), `[]int(nil)`}, + {"%#v", []int{}, `[]int{}`}, + {"%#v", array, `[5]int{1, 2, 3, 4, 5}`}, + {"%#v", &array, `&[5]int{1, 2, 3, 4, 5}`}, + {"%#v", iarray, `[4]interface {}{1, "hello", 2.5, interface {}(nil)}`}, + {"%#v", &iarray, `&[4]interface {}{1, "hello", 2.5, interface {}(nil)}`}, + {"%#v", map[int]byte(nil), `map[int]uint8(nil)`}, + {"%#v", map[int]byte{}, `map[int]uint8{}`}, // slices with other formats {"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`}, @@ -385,11 +407,11 @@ var fmttests = []struct { // Formatter {"%x", F(1), "<x=F(1)>"}, {"%x", G(2), "2"}, - {"%+v", S{F(4), G(5)}, "{f:<v=F(4)> g:5}"}, + {"%+v", S{F(4), G(5)}, "{F:<v=F(4)> G:5}"}, // GoStringer {"%#v", G(6), "GoString(6)"}, - {"%#v", S{F(7), G(8)}, "fmt_test.S{f:<v=F(7)>, g:GoString(8)}"}, + {"%#v", S{F(7), G(8)}, "fmt_test.S{F:<v=F(7)>, G:GoString(8)}"}, // %T {"%T", (4 - 3i), "complex128"}, @@ -409,6 +431,10 @@ var fmttests = []struct { {"%p", make([]int, 1), "0xPTR"}, {"%p", 27, "%!p(int=27)"}, // not a pointer at all + // %d on Stringer should give integer if possible + {"%s", time.Time{}.Month(), "January"}, + {"%d", time.Time{}.Month(), "1"}, + // erroneous things {"%s %", "hello", "hello %!(NOVERB)"}, {"%s %.2", "hello", "hello %!(NOVERB)"}, @@ -474,74 +500,52 @@ func BenchmarkSprintfPrefixedInt(b *testing.B) { } } -func TestCountMallocs(t *testing.T) { - if testing.Short() { - return - } - runtime.UpdateMemStats() - mallocs := 0 - runtime.MemStats.Mallocs - for i := 0; i < 100; i++ { - Sprintf("") - } - runtime.UpdateMemStats() - mallocs += runtime.MemStats.Mallocs - Printf("mallocs per Sprintf(\"\"): %d\n", mallocs/100) - runtime.UpdateMemStats() - mallocs = 0 - runtime.MemStats.Mallocs - for i := 0; i < 100; i++ { - Sprintf("xxx") - } - runtime.UpdateMemStats() - mallocs += runtime.MemStats.Mallocs - Printf("mallocs per Sprintf(\"xxx\"): %d\n", mallocs/100) - runtime.UpdateMemStats() - mallocs = 0 - runtime.MemStats.Mallocs - for i := 0; i < 100; i++ { - Sprintf("%x", i) - } - runtime.UpdateMemStats() - mallocs += runtime.MemStats.Mallocs - Printf("mallocs per Sprintf(\"%%x\"): %d\n", mallocs/100) - runtime.UpdateMemStats() - mallocs = 0 - runtime.MemStats.Mallocs - for i := 0; i < 100; i++ { - Sprintf("%s", "hello") - } - runtime.UpdateMemStats() - mallocs += runtime.MemStats.Mallocs - Printf("mallocs per Sprintf(\"%%s\"): %d\n", mallocs/100) - runtime.UpdateMemStats() - mallocs = 0 - runtime.MemStats.Mallocs - for i := 0; i < 100; i++ { - Sprintf("%x %x", i, i) - } - runtime.UpdateMemStats() - mallocs += runtime.MemStats.Mallocs - Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/100) - buf := new(bytes.Buffer) - runtime.UpdateMemStats() - mallocs = 0 - runtime.MemStats.Mallocs - for i := 0; i < 100; i++ { - buf.Reset() - Fprintf(buf, "%x %x %x", i, i, i) +func BenchmarkSprintfFloat(b *testing.B) { + for i := 0; i < b.N; i++ { + Sprintf("%g", 5.23184) } - runtime.UpdateMemStats() - mallocs += runtime.MemStats.Mallocs - Printf("mallocs per Fprintf(buf, \"%%x %%x %%x\"): %d\n", mallocs/100) - runtime.UpdateMemStats() - mallocs = 0 - runtime.MemStats.Mallocs - for i := 0; i < 100; i++ { - buf.Reset() - Fprintf(buf, "%s", "hello") +} + +var mallocBuf bytes.Buffer + +var mallocTest = []struct { + count int + desc string + fn func() +}{ + {0, `Sprintf("")`, func() { Sprintf("") }}, + {1, `Sprintf("xxx")`, func() { Sprintf("xxx") }}, + {1, `Sprintf("%x")`, func() { Sprintf("%x", 7) }}, + {2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }}, + {1, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }}, + // For %g we use a float32, not float64, to guarantee passing the argument + // does not need to allocate memory to store the result in a pointer-sized word. + {2, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }}, + {0, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }}, + {1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }}, +} + +var _ bytes.Buffer + +func TestCountMallocs(t *testing.T) { + for _, mt := range mallocTest { + const N = 100 + runtime.UpdateMemStats() + mallocs := 0 - runtime.MemStats.Mallocs + for i := 0; i < N; i++ { + mt.fn() + } + runtime.UpdateMemStats() + mallocs += runtime.MemStats.Mallocs + if mallocs/N > uint64(mt.count) { + t.Errorf("%s: expected %d mallocs, got %d", mt.desc, mt.count, mallocs/N) + } } - runtime.UpdateMemStats() - mallocs += runtime.MemStats.Mallocs - Printf("mallocs per Fprintf(buf, \"%%s\"): %d\n", mallocs/100) } type flagPrinter struct{} -func (*flagPrinter) Format(f State, c int) { +func (*flagPrinter) Format(f State, c rune) { s := "%" for i := 0; i < 128; i++ { if f.Flag(i) { @@ -741,7 +745,7 @@ type PanicF struct { } // Value receiver. -func (p PanicF) Format(f State, c int) { +func (p PanicF) Format(f State, c rune) { panic(p.message) } @@ -751,9 +755,9 @@ var panictests = []struct { out string }{ // String - {"%d", (*Panic)(nil), "<nil>"}, // nil pointer special case - {"%d", Panic{io.ErrUnexpectedEOF}, "%d(PANIC=unexpected EOF)"}, - {"%d", Panic{3}, "%d(PANIC=3)"}, + {"%s", (*Panic)(nil), "<nil>"}, // nil pointer special case + {"%s", Panic{io.ErrUnexpectedEOF}, "%s(PANIC=unexpected EOF)"}, + {"%s", Panic{3}, "%s(PANIC=3)"}, // GoString {"%#v", (*Panic)(nil), "<nil>"}, // nil pointer special case {"%#v", Panic{io.ErrUnexpectedEOF}, "%v(PANIC=unexpected EOF)"}, @@ -772,3 +776,37 @@ func TestPanics(t *testing.T) { } } } + +// Test that erroneous String routine doesn't cause fatal recursion. +var recurCount = 0 + +type Recur struct { + i int + failed *bool +} + +func (r Recur) String() string { + if recurCount++; recurCount > 10 { + *r.failed = true + return "FAIL" + } + // This will call badVerb. Before the fix, that would cause us to recur into + // this routine to print %!p(value). Now we don't call the user's method + // during an error. + return Sprintf("recur@%p value: %d", r, r.i) +} + +func TestBadVerbRecursion(t *testing.T) { + failed := false + r := Recur{3, &failed} + Sprintf("recur@%p value: %d\n", &r, r.i) + if failed { + t.Error("fail with pointer") + } + failed = false + r = Recur{4, &failed} + Sprintf("recur@%p, value: %d\n", r, r.i) + if failed { + t.Error("fail with value") + } +} diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go index 24b15a286..78d9e998b 100644 --- a/src/pkg/fmt/format.go +++ b/src/pkg/fmt/format.go @@ -8,7 +8,7 @@ import ( "bytes" "strconv" "unicode" - "utf8" + "unicode/utf8" ) const ( @@ -154,12 +154,17 @@ func putint(buf []byte, base, val uint64, digits string) int { return i - 1 } +var ( + trueBytes = []byte("true") + falseBytes = []byte("false") +) + // fmt_boolean formats a boolean. func (f *fmt) fmt_boolean(v bool) { if v { - f.padString("true") + f.pad(trueBytes) } else { - f.padString("false") + f.pad(falseBytes) } } @@ -242,8 +247,8 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) { } // If we want a quoted char for %#U, move the data up to make room. - if f.unicode && f.uniQuote && a >= 0 && a <= unicode.MaxRune && unicode.IsPrint(int(a)) { - runeWidth := utf8.RuneLen(int(a)) + if f.unicode && f.uniQuote && a >= 0 && a <= unicode.MaxRune && unicode.IsPrint(rune(a)) { + runeWidth := utf8.RuneLen(rune(a)) width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote copy(buf[i-width:], buf[i:]) // guaranteed to have enough room. i -= width @@ -253,7 +258,7 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) { j++ buf[j] = '\'' j++ - utf8.EncodeRune(buf[j:], int(a)) + utf8.EncodeRune(buf[j:], rune(a)) j += runeWidth buf[j] = '\'' } @@ -283,31 +288,18 @@ func (f *fmt) fmt_s(s string) { } // fmt_sx formats a string as a hexadecimal encoding of its bytes. -func (f *fmt) fmt_sx(s string) { - t := "" +func (f *fmt) fmt_sx(s, digits string) { + // TODO: Avoid buffer by pre-padding. + var b bytes.Buffer for i := 0; i < len(s); i++ { if i > 0 && f.space { - t += " " + b.WriteByte(' ') } v := s[i] - t += string(ldigits[v>>4]) - t += string(ldigits[v&0xF]) + b.WriteByte(digits[v>>4]) + b.WriteByte(digits[v&0xF]) } - f.padString(t) -} - -// fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes. -func (f *fmt) fmt_sX(s string) { - t := "" - for i := 0; i < len(s); i++ { - if i > 0 && f.space { - t += " " - } - v := s[i] - t += string(udigits[v>>4]) - t += string(udigits[v&0xF]) - } - f.padString(t) + f.pad(b.Bytes()) } // fmt_q formats a string as a double-quoted, escaped Go string constant. @@ -329,13 +321,13 @@ func (f *fmt) fmt_q(s string) { // fmt_qc formats the integer as a single-quoted, escaped Go character constant. // If the character is not valid Unicode, it will print '\ufffd'. func (f *fmt) fmt_qc(c int64) { - var quoted string + var quoted []byte if f.plus { - quoted = strconv.QuoteRuneToASCII(int(c)) + quoted = strconv.AppendQuoteRuneToASCII(f.intbuf[0:0], rune(c)) } else { - quoted = strconv.QuoteRune(int(c)) + quoted = strconv.AppendQuoteRune(f.intbuf[0:0], rune(c)) } - f.padString(quoted) + f.pad(quoted) } // floating-point @@ -347,60 +339,73 @@ func doPrec(f *fmt, def int) int { return def } -// Add a plus sign or space to the floating-point string representation if missing and required. -func (f *fmt) plusSpace(s string) { - if s[0] != '-' { +// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...). +func (f *fmt) formatFloat(v float64, verb byte, prec, n int) { + // We leave one byte at the beginning of f.intbuf for a sign if needed, + // and make it a space, which we might be able to use. + f.intbuf[0] = ' ' + slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n) + // Add a plus sign or space to the floating-point string representation if missing and required. + // The formatted number starts at slice[1]. + switch slice[1] { + case '-', '+': + // We're set; drop the leading space. + slice = slice[1:] + default: + // There's no sign, but we might need one. if f.plus { - s = "+" + s + slice[0] = '+' } else if f.space { - s = " " + s + // space is already there + } else { + slice = slice[1:] } } - f.padString(s) + f.pad(slice) } // fmt_e64 formats a float64 in the form -1.23e+12. -func (f *fmt) fmt_e64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'e', doPrec(f, 6))) } +func (f *fmt) fmt_e64(v float64) { f.formatFloat(v, 'e', doPrec(f, 6), 64) } // fmt_E64 formats a float64 in the form -1.23E+12. -func (f *fmt) fmt_E64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'E', doPrec(f, 6))) } +func (f *fmt) fmt_E64(v float64) { f.formatFloat(v, 'E', doPrec(f, 6), 64) } // fmt_f64 formats a float64 in the form -1.23. -func (f *fmt) fmt_f64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'f', doPrec(f, 6))) } +func (f *fmt) fmt_f64(v float64) { f.formatFloat(v, 'f', doPrec(f, 6), 64) } // fmt_g64 formats a float64 in the 'f' or 'e' form according to size. -func (f *fmt) fmt_g64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'g', doPrec(f, -1))) } +func (f *fmt) fmt_g64(v float64) { f.formatFloat(v, 'g', doPrec(f, -1), 64) } // fmt_g64 formats a float64 in the 'f' or 'E' form according to size. -func (f *fmt) fmt_G64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'G', doPrec(f, -1))) } +func (f *fmt) fmt_G64(v float64) { f.formatFloat(v, 'G', doPrec(f, -1), 64) } // fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2). -func (f *fmt) fmt_fb64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'b', 0)) } +func (f *fmt) fmt_fb64(v float64) { f.formatFloat(v, 'b', 0, 64) } // float32 // cannot defer to float64 versions // because it will get rounding wrong in corner cases. // fmt_e32 formats a float32 in the form -1.23e+12. -func (f *fmt) fmt_e32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'e', doPrec(f, 6))) } +func (f *fmt) fmt_e32(v float32) { f.formatFloat(float64(v), 'e', doPrec(f, 6), 32) } // fmt_E32 formats a float32 in the form -1.23E+12. -func (f *fmt) fmt_E32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'E', doPrec(f, 6))) } +func (f *fmt) fmt_E32(v float32) { f.formatFloat(float64(v), 'E', doPrec(f, 6), 32) } // fmt_f32 formats a float32 in the form -1.23. -func (f *fmt) fmt_f32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'f', doPrec(f, 6))) } +func (f *fmt) fmt_f32(v float32) { f.formatFloat(float64(v), 'f', doPrec(f, 6), 32) } // fmt_g32 formats a float32 in the 'f' or 'e' form according to size. -func (f *fmt) fmt_g32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'g', doPrec(f, -1))) } +func (f *fmt) fmt_g32(v float32) { f.formatFloat(float64(v), 'g', doPrec(f, -1), 32) } // fmt_G32 formats a float32 in the 'f' or 'E' form according to size. -func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'G', doPrec(f, -1))) } +func (f *fmt) fmt_G32(v float32) { f.formatFloat(float64(v), 'G', doPrec(f, -1), 32) } // fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2). -func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.Ftoa32(v, 'b', 0)) } +func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) } // fmt_c64 formats a complex64 according to the verb. -func (f *fmt) fmt_c64(v complex64, verb int) { +func (f *fmt) fmt_c64(v complex64, verb rune) { f.buf.WriteByte('(') r := real(v) for i := 0; ; i++ { @@ -426,7 +431,7 @@ func (f *fmt) fmt_c64(v complex64, verb int) { } // fmt_c128 formats a complex128 according to the verb. -func (f *fmt) fmt_c128(v complex128, verb int) { +func (f *fmt) fmt_c128(v complex128, verb rune) { f.buf.WriteByte('(') r := real(v) for i := 0; ; i++ { diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go index 738734908..3b7d3464e 100644 --- a/src/pkg/fmt/print.go +++ b/src/pkg/fmt/print.go @@ -6,11 +6,13 @@ package fmt import ( "bytes" + "errors" "io" "os" "reflect" + "sync" "unicode" - "utf8" + "unicode/utf8" ) // Some constants in the form of bytes, to avoid string overhead. @@ -36,7 +38,7 @@ var ( // the flags and options for the operand's format specifier. type State interface { // Write is the function to call to emit formatted output to be printed. - Write(b []byte) (ret int, err os.Error) + Write(b []byte) (ret int, err error) // Width returns the value of the width option and whether it has been set. Width() (wid int, ok bool) // Precision returns the value of the precision option and whether it has been set. @@ -50,7 +52,7 @@ type State interface { // The implementation of Format may call Sprintf or Fprintf(f) etc. // to generate its output. type Formatter interface { - Format(f State, c int) + Format(f State, c rune) } // Stringer is implemented by any value that has a String method, @@ -72,40 +74,49 @@ type GoStringer interface { type pp struct { n int panicking bool + erroring bool // printing an error condition buf bytes.Buffer - runeBuf [utf8.UTFMax]byte - fmt fmt + // field holds the current item, as an interface{}. + field interface{} + // value holds the current item, as a reflect.Value, and will be + // the zero Value if the item has not been reflected. + value reflect.Value + runeBuf [utf8.UTFMax]byte + fmt fmt } // A cache holds a set of reusable objects. -// The buffered channel holds the currently available objects. +// The slice is a stack (LIFO). // If more are needed, the cache creates them by calling new. type cache struct { - saved chan interface{} + mu sync.Mutex + saved []interface{} new func() interface{} } func (c *cache) put(x interface{}) { - select { - case c.saved <- x: - // saved in cache - default: - // discard + c.mu.Lock() + if len(c.saved) < cap(c.saved) { + c.saved = append(c.saved, x) } + c.mu.Unlock() } func (c *cache) get() interface{} { - select { - case x := <-c.saved: - return x // reused from cache - default: + c.mu.Lock() + n := len(c.saved) + if n == 0 { + c.mu.Unlock() return c.new() } - panic("not reached") + x := c.saved[n-1] + c.saved = c.saved[0 : n-1] + c.mu.Unlock() + return x } func newCache(f func() interface{}) *cache { - return &cache{make(chan interface{}, 100), f} + return &cache{saved: make([]interface{}, 0, 100), new: f} } var ppFree = newCache(func() interface{} { return new(pp) }) @@ -114,6 +125,7 @@ var ppFree = newCache(func() interface{} { return new(pp) }) func newPrinter() *pp { p := ppFree.get().(*pp) p.panicking = false + p.erroring = false p.fmt.init(&p.buf) return p } @@ -125,6 +137,8 @@ func (p *pp) free() { return } p.buf.Reset() + p.field = nil + p.value = reflect.Value{} ppFree.put(p) } @@ -148,13 +162,13 @@ func (p *pp) Flag(b int) bool { return false } -func (p *pp) add(c int) { +func (p *pp) add(c rune) { p.buf.WriteRune(c) } // Implement Write so we can call Fprintf on a pp (through State), for // recursive use in custom verbs. -func (p *pp) Write(b []byte) (ret int, err os.Error) { +func (p *pp) Write(b []byte) (ret int, err error) { return p.buf.Write(b) } @@ -162,7 +176,7 @@ func (p *pp) Write(b []byte) (ret int, err os.Error) { // Fprintf formats according to a format specifier and writes to w. // It returns the number of bytes written and any write error encountered. -func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err os.Error) { +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { p := newPrinter() p.doPrintf(format, a) n64, err := p.buf.WriteTo(w) @@ -172,7 +186,7 @@ func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err os.Error) // Printf formats according to a format specifier and writes to standard output. // It returns the number of bytes written and any write error encountered. -func Printf(format string, a ...interface{}) (n int, err os.Error) { +func Printf(format string, a ...interface{}) (n int, err error) { return Fprintf(os.Stdout, format, a...) } @@ -186,9 +200,9 @@ func Sprintf(format string, a ...interface{}) string { } // Errorf formats according to a format specifier and returns the string -// converted to an os.ErrorString, which satisfies the os.Error interface. -func Errorf(format string, a ...interface{}) os.Error { - return os.NewError(Sprintf(format, a...)) +// as a value that satisfies error. +func Errorf(format string, a ...interface{}) error { + return errors.New(Sprintf(format, a...)) } // These routines do not take a format string @@ -196,7 +210,7 @@ func Errorf(format string, a ...interface{}) os.Error { // Fprint formats using the default formats for its operands and writes to w. // Spaces are added between operands when neither is a string. // It returns the number of bytes written and any write error encountered. -func Fprint(w io.Writer, a ...interface{}) (n int, err os.Error) { +func Fprint(w io.Writer, a ...interface{}) (n int, err error) { p := newPrinter() p.doPrint(a, false, false) n64, err := p.buf.WriteTo(w) @@ -207,7 +221,7 @@ func Fprint(w io.Writer, a ...interface{}) (n int, err os.Error) { // Print formats using the default formats for its operands and writes to standard output. // Spaces are added between operands when neither is a string. // It returns the number of bytes written and any write error encountered. -func Print(a ...interface{}) (n int, err os.Error) { +func Print(a ...interface{}) (n int, err error) { return Fprint(os.Stdout, a...) } @@ -228,7 +242,7 @@ func Sprint(a ...interface{}) string { // Fprintln formats using the default formats for its operands and writes to w. // Spaces are always added between operands and a newline is appended. // It returns the number of bytes written and any write error encountered. -func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) { +func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { p := newPrinter() p.doPrint(a, true, true) n64, err := p.buf.WriteTo(w) @@ -239,7 +253,7 @@ func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) { // Println formats using the default formats for its operands and writes to standard output. // Spaces are always added between operands and a newline is appended. // It returns the number of bytes written and any write error encountered. -func Println(a ...interface{}) (n int, err os.Error) { +func Println(a ...interface{}) (n int, err error) { return Fprintln(os.Stdout, a...) } @@ -258,10 +272,8 @@ func Sprintln(a ...interface{}) string { // the thing inside the interface, not the interface itself. func getField(v reflect.Value, i int) reflect.Value { val := v.Field(i) - if i := val; i.Kind() == reflect.Interface { - if inter := i.Interface(); inter != nil { - return reflect.ValueOf(inter) - } + if val.Kind() == reflect.Interface && !val.IsNil() { + val = val.Elem() } return val } @@ -288,41 +300,48 @@ func (p *pp) unknownType(v interface{}) { p.buf.WriteByte('?') } -func (p *pp) badVerb(verb int, val interface{}) { +func (p *pp) badVerb(verb rune) { + p.erroring = true p.add('%') p.add('!') p.add(verb) p.add('(') - if val == nil { - p.buf.Write(nilAngleBytes) - } else { - p.buf.WriteString(reflect.TypeOf(val).String()) + switch { + case p.field != nil: + p.buf.WriteString(reflect.TypeOf(p.field).String()) + p.add('=') + p.printField(p.field, 'v', false, false, 0) + case p.value.IsValid(): + p.buf.WriteString(p.value.Type().String()) p.add('=') - p.printField(val, 'v', false, false, 0) + p.printValue(p.value, 'v', false, false, 0) + default: + p.buf.Write(nilAngleBytes) } p.add(')') + p.erroring = false } -func (p *pp) fmtBool(v bool, verb int, value interface{}) { +func (p *pp) fmtBool(v bool, verb rune) { switch verb { case 't', 'v': p.fmt.fmt_boolean(v) default: - p.badVerb(verb, value) + p.badVerb(verb) } } // fmtC formats a rune for the 'c' format. func (p *pp) fmtC(c int64) { - rune := int(c) // Check for overflow. - if int64(rune) != c { - rune = utf8.RuneError + r := rune(c) // Check for overflow. + if int64(r) != c { + r = utf8.RuneError } - w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], rune) + w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], r) p.fmt.pad(p.runeBuf[0:w]) } -func (p *pp) fmtInt64(v int64, verb int, value interface{}) { +func (p *pp) fmtInt64(v int64, verb rune) { switch verb { case 'b': p.fmt.integer(v, 2, signed, ldigits) @@ -336,7 +355,7 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) { if 0 <= v && v <= unicode.MaxRune { p.fmt.fmt_qc(v) } else { - p.badVerb(verb, value) + p.badVerb(verb) } case 'x': p.fmt.integer(v, 16, signed, ldigits) @@ -345,7 +364,7 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) { case 'X': p.fmt.integer(v, 16, signed, udigits) default: - p.badVerb(verb, value) + p.badVerb(verb) } } @@ -380,7 +399,7 @@ func (p *pp) fmtUnicode(v int64) { p.fmt.sharp = sharp } -func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) { +func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) { switch verb { case 'b': p.fmt.integer(int64(v), 2, unsigned, ldigits) @@ -400,7 +419,7 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) { if 0 <= v && v <= unicode.MaxRune { p.fmt.fmt_qc(int64(v)) } else { - p.badVerb(verb, value) + p.badVerb(verb) } case 'x': p.fmt.integer(int64(v), 16, unsigned, ldigits) @@ -409,11 +428,11 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) { case 'U': p.fmtUnicode(int64(v)) default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtFloat32(v float32, verb int, value interface{}) { +func (p *pp) fmtFloat32(v float32, verb rune) { switch verb { case 'b': p.fmt.fmt_fb32(v) @@ -428,11 +447,11 @@ func (p *pp) fmtFloat32(v float32, verb int, value interface{}) { case 'G': p.fmt.fmt_G32(v) default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtFloat64(v float64, verb int, value interface{}) { +func (p *pp) fmtFloat64(v float64, verb rune) { switch verb { case 'b': p.fmt.fmt_fb64(v) @@ -447,33 +466,33 @@ func (p *pp) fmtFloat64(v float64, verb int, value interface{}) { case 'G': p.fmt.fmt_G64(v) default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) { +func (p *pp) fmtComplex64(v complex64, verb rune) { switch verb { case 'e', 'E', 'f', 'F', 'g', 'G': p.fmt.fmt_c64(v, verb) case 'v': p.fmt.fmt_c64(v, 'g') default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) { +func (p *pp) fmtComplex128(v complex128, verb rune) { switch verb { case 'e', 'E', 'f', 'F', 'g', 'G': p.fmt.fmt_c128(v, verb) case 'v': p.fmt.fmt_c128(v, 'g') default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) { +func (p *pp) fmtString(v string, verb rune, goSyntax bool) { switch verb { case 'v': if goSyntax { @@ -484,17 +503,17 @@ func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) { case 's': p.fmt.fmt_s(v) case 'x': - p.fmt.fmt_sx(v) + p.fmt.fmt_sx(v, ldigits) case 'X': - p.fmt.fmt_sX(v) + p.fmt.fmt_sx(v, udigits) case 'q': p.fmt.fmt_q(v) default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) { +func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) { if verb == 'v' || verb == 'd' { if goSyntax { p.buf.Write(bytesBytes) @@ -523,28 +542,28 @@ func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interf case 's': p.fmt.fmt_s(s) case 'x': - p.fmt.fmt_sx(s) + p.fmt.fmt_sx(s, ldigits) case 'X': - p.fmt.fmt_sX(s) + p.fmt.fmt_sx(s, udigits) case 'q': p.fmt.fmt_q(s) default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) { +func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) { var u uintptr switch value.Kind() { case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer: u = value.Pointer() default: - p.badVerb(verb, field) + p.badVerb(verb) return } if goSyntax { p.add('(') - p.buf.WriteString(reflect.TypeOf(field).String()) + p.buf.WriteString(value.Type().String()) p.add(')') p.add('(') if u == 0 { @@ -565,12 +584,12 @@ var ( uintptrBits = reflect.TypeOf(uintptr(0)).Bits() ) -func (p *pp) catchPanic(val interface{}, verb int) { +func (p *pp) catchPanic(field interface{}, verb rune) { if err := recover(); err != nil { // If it's a nil pointer, just say "<nil>". The likeliest causes are a // Stringer that fails to guard against nil or a nil pointer for a // value receiver, and in either case, "<nil>" is a nice result. - if v := reflect.ValueOf(val); v.Kind() == reflect.Ptr && v.IsNil() { + if v := reflect.ValueOf(field); v.Kind() == reflect.Ptr && v.IsNil() { p.buf.Write(nilAngleBytes) return } @@ -590,16 +609,77 @@ func (p *pp) catchPanic(val interface{}, verb int) { } } -func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) { +func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString, handled bool) { + if p.erroring { + return + } + // Is it a Formatter? + if formatter, ok := p.field.(Formatter); ok { + handled = true + wasString = false + defer p.catchPanic(p.field, verb) + formatter.Format(p, verb) + return + } + // Must not touch flags before Formatter looks at them. + if plus { + p.fmt.plus = false + } + + // If we're doing Go syntax and the field knows how to supply it, take care of it now. + if goSyntax { + p.fmt.sharp = false + if stringer, ok := p.field.(GoStringer); ok { + wasString = false + handled = true + defer p.catchPanic(p.field, verb) + // Print the result of GoString unadorned. + p.fmtString(stringer.GoString(), 's', false) + return + } + } else { + // If a string is acceptable according to the format, see if + // the value satisfies one of the string-valued interfaces. + // Println etc. set verb to %v, which is "stringable". + switch verb { + case 'v', 's', 'x', 'X', 'q': + // Is it an error or Stringer? + // The duplication in the bodies is necessary: + // setting wasString and handled, and deferring catchPanic, + // must happen before calling the method. + switch v := p.field.(type) { + case error: + wasString = false + handled = true + defer p.catchPanic(p.field, verb) + p.printField(v.Error(), verb, plus, false, depth) + return + + case Stringer: + wasString = false + handled = true + defer p.catchPanic(p.field, verb) + p.printField(v.String(), verb, plus, false, depth) + return + } + } + } + handled = false + return +} + +func (p *pp) printField(field interface{}, verb rune, plus, goSyntax bool, depth int) (wasString bool) { if field == nil { if verb == 'T' || verb == 'v' { p.buf.Write(nilAngleBytes) } else { - p.badVerb(verb, field) + p.badVerb(verb) } return false } + p.field = field + p.value = reflect.Value{} // Special processing considerations. // %T (the value's type) and %p (its address) are special; we always do them first. switch verb { @@ -607,124 +687,131 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth p.printField(reflect.TypeOf(field).String(), 's', false, false, 0) return false case 'p': - p.fmtPointer(field, reflect.ValueOf(field), verb, goSyntax) + p.fmtPointer(reflect.ValueOf(field), verb, goSyntax) return false } - // Is it a Formatter? - if formatter, ok := field.(Formatter); ok { - defer p.catchPanic(field, verb) - formatter.Format(p, verb) - return false // this value is not a string - } - // Must not touch flags before Formatter looks at them. - if plus { - p.fmt.plus = false - } - // If we're doing Go syntax and the field knows how to supply it, take care of it now. - if goSyntax { - p.fmt.sharp = false - if stringer, ok := field.(GoStringer); ok { - defer p.catchPanic(field, verb) - // Print the result of GoString unadorned. - p.fmtString(stringer.GoString(), 's', false, field) - return false // this value is not a string - } - } else { - // Is it a Stringer? - if stringer, ok := field.(Stringer); ok { - defer p.catchPanic(field, verb) - p.printField(stringer.String(), verb, plus, false, depth) - return false // this value is not a string - } + if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled { + return wasString } // Some types can be done without reflection. switch f := field.(type) { case bool: - p.fmtBool(f, verb, field) - return false + p.fmtBool(f, verb) case float32: - p.fmtFloat32(f, verb, field) - return false + p.fmtFloat32(f, verb) case float64: - p.fmtFloat64(f, verb, field) - return false + p.fmtFloat64(f, verb) case complex64: - p.fmtComplex64(complex64(f), verb, field) - return false + p.fmtComplex64(complex64(f), verb) case complex128: - p.fmtComplex128(f, verb, field) - return false + p.fmtComplex128(f, verb) case int: - p.fmtInt64(int64(f), verb, field) - return false + p.fmtInt64(int64(f), verb) case int8: - p.fmtInt64(int64(f), verb, field) - return false + p.fmtInt64(int64(f), verb) case int16: - p.fmtInt64(int64(f), verb, field) - return false + p.fmtInt64(int64(f), verb) case int32: - p.fmtInt64(int64(f), verb, field) - return false + p.fmtInt64(int64(f), verb) case int64: - p.fmtInt64(f, verb, field) - return false + p.fmtInt64(f, verb) case uint: - p.fmtUint64(uint64(f), verb, goSyntax, field) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint8: - p.fmtUint64(uint64(f), verb, goSyntax, field) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint16: - p.fmtUint64(uint64(f), verb, goSyntax, field) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint32: - p.fmtUint64(uint64(f), verb, goSyntax, field) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint64: - p.fmtUint64(f, verb, goSyntax, field) - return false + p.fmtUint64(f, verb, goSyntax) case uintptr: - p.fmtUint64(uint64(f), verb, goSyntax, field) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case string: - p.fmtString(f, verb, goSyntax, field) - return verb == 's' || verb == 'v' + p.fmtString(f, verb, goSyntax) + wasString = verb == 's' || verb == 'v' case []byte: - p.fmtBytes(f, verb, goSyntax, depth, field) - return verb == 's' + p.fmtBytes(f, verb, goSyntax, depth) + wasString = verb == 's' + default: + // Need to use reflection + return p.printReflectValue(reflect.ValueOf(field), verb, plus, goSyntax, depth) } + p.field = nil + return +} - // Need to use reflection - value := reflect.ValueOf(field) +// printValue is like printField but starts with a reflect value, not an interface{} value. +func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) { + if !value.IsValid() { + if verb == 'T' || verb == 'v' { + p.buf.Write(nilAngleBytes) + } else { + p.badVerb(verb) + } + return false + } + + // Special processing considerations. + // %T (the value's type) and %p (its address) are special; we always do them first. + switch verb { + case 'T': + p.printField(value.Type().String(), 's', false, false, 0) + return false + case 'p': + p.fmtPointer(value, verb, goSyntax) + return false + } + + // Handle values with special methods. + // Call always, even when field == nil, because handleMethods clears p.fmt.plus for us. + p.field = nil // Make sure it's cleared, for safety. + if value.CanInterface() { + p.field = value.Interface() + } + if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled { + return wasString + } + + return p.printReflectValue(value, verb, plus, goSyntax, depth) +} +// printReflectValue is the fallback for both printField and printValue. +// It uses reflect to print the value. +func (p *pp) printReflectValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) { + oldValue := p.value + p.value = value BigSwitch: switch f := value; f.Kind() { case reflect.Bool: - p.fmtBool(f.Bool(), verb, field) + p.fmtBool(f.Bool(), verb) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p.fmtInt64(f.Int(), verb, field) + p.fmtInt64(f.Int(), verb) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p.fmtUint64(uint64(f.Uint()), verb, goSyntax, field) + p.fmtUint64(uint64(f.Uint()), verb, goSyntax) case reflect.Float32, reflect.Float64: if f.Type().Size() == 4 { - p.fmtFloat32(float32(f.Float()), verb, field) + p.fmtFloat32(float32(f.Float()), verb) } else { - p.fmtFloat64(float64(f.Float()), verb, field) + p.fmtFloat64(float64(f.Float()), verb) } case reflect.Complex64, reflect.Complex128: if f.Type().Size() == 8 { - p.fmtComplex64(complex64(f.Complex()), verb, field) + p.fmtComplex64(complex64(f.Complex()), verb) } else { - p.fmtComplex128(complex128(f.Complex()), verb, field) + p.fmtComplex128(complex128(f.Complex()), verb) } case reflect.String: - p.fmtString(f.String(), verb, goSyntax, field) + p.fmtString(f.String(), verb, goSyntax) case reflect.Map: if goSyntax { p.buf.WriteString(f.Type().String()) + if f.IsNil() { + p.buf.WriteString("(nil)") + break + } p.buf.WriteByte('{') } else { p.buf.Write(mapBytes) @@ -738,9 +825,9 @@ BigSwitch: p.buf.WriteByte(' ') } } - p.printField(key.Interface(), verb, plus, goSyntax, depth+1) + p.printValue(key, verb, plus, goSyntax, depth+1) p.buf.WriteByte(':') - p.printField(f.MapIndex(key).Interface(), verb, plus, goSyntax, depth+1) + p.printValue(f.MapIndex(key), verb, plus, goSyntax, depth+1) } if goSyntax { p.buf.WriteByte('}') @@ -749,7 +836,7 @@ BigSwitch: } case reflect.Struct: if goSyntax { - p.buf.WriteString(reflect.TypeOf(field).String()) + p.buf.WriteString(value.Type().String()) } p.add('{') v := f @@ -768,20 +855,20 @@ BigSwitch: p.buf.WriteByte(':') } } - p.printField(getField(v, i).Interface(), verb, plus, goSyntax, depth+1) + p.printValue(getField(v, i), verb, plus, goSyntax, depth+1) } p.buf.WriteByte('}') case reflect.Interface: value := f.Elem() if !value.IsValid() { if goSyntax { - p.buf.WriteString(reflect.TypeOf(field).String()) + p.buf.WriteString(f.Type().String()) p.buf.Write(nilParenBytes) } else { p.buf.Write(nilAngleBytes) } } else { - return p.printField(value.Interface(), verb, plus, goSyntax, depth+1) + wasString = p.printValue(value, verb, plus, goSyntax, depth+1) } case reflect.Array, reflect.Slice: // Byte slices are special. @@ -797,11 +884,16 @@ BigSwitch: for i := range bytes { bytes[i] = byte(f.Index(i).Uint()) } - p.fmtBytes(bytes, verb, goSyntax, depth, field) - return verb == 's' + p.fmtBytes(bytes, verb, goSyntax, depth) + wasString = verb == 's' + break } if goSyntax { - p.buf.WriteString(reflect.TypeOf(field).String()) + p.buf.WriteString(value.Type().String()) + if f.Kind() == reflect.Slice && f.IsNil() { + p.buf.WriteString("(nil)") + break + } p.buf.WriteByte('{') } else { p.buf.WriteByte('[') @@ -814,7 +906,7 @@ BigSwitch: p.buf.WriteByte(' ') } } - p.printField(f.Index(i).Interface(), verb, plus, goSyntax, depth+1) + p.printValue(f.Index(i), verb, plus, goSyntax, depth+1) } if goSyntax { p.buf.WriteByte('}') @@ -829,17 +921,17 @@ BigSwitch: switch a := f.Elem(); a.Kind() { case reflect.Array, reflect.Slice: p.buf.WriteByte('&') - p.printField(a.Interface(), verb, plus, goSyntax, depth+1) + p.printValue(a, verb, plus, goSyntax, depth+1) break BigSwitch case reflect.Struct: p.buf.WriteByte('&') - p.printField(a.Interface(), verb, plus, goSyntax, depth+1) + p.printValue(a, verb, plus, goSyntax, depth+1) break BigSwitch } } if goSyntax { p.buf.WriteByte('(') - p.buf.WriteString(reflect.TypeOf(field).String()) + p.buf.WriteString(value.Type().String()) p.buf.WriteByte(')') p.buf.WriteByte('(') if v == 0 { @@ -856,11 +948,12 @@ BigSwitch: } p.fmt0x64(uint64(v), true) case reflect.Chan, reflect.Func, reflect.UnsafePointer: - p.fmtPointer(field, value, verb, goSyntax) + p.fmtPointer(value, verb, goSyntax) default: p.unknownType(f) } - return false + p.value = oldValue + return wasString } // intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int. diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go index 259451d02..281525112 100644 --- a/src/pkg/fmt/scan.go +++ b/src/pkg/fmt/scan.go @@ -6,6 +6,7 @@ package fmt import ( "bytes" + "errors" "io" "math" "os" @@ -13,7 +14,7 @@ import ( "strconv" "strings" "unicode" - "utf8" + "unicode/utf8" ) // runeUnreader is the interface to something that can unread runes. @@ -21,7 +22,7 @@ import ( // a local buffer will be used to back up the input, but its contents // will be lost when Scan returns. type runeUnreader interface { - UnreadRune() os.Error + UnreadRune() error } // ScanState represents the scanner state passed to custom scanners. @@ -32,9 +33,9 @@ type ScanState interface { // If invoked during Scanln, Fscanln, or Sscanln, ReadRune() will // return EOF after returning the first '\n' or when reading beyond // the specified width. - ReadRune() (rune int, size int, err os.Error) + ReadRune() (r rune, size int, err error) // UnreadRune causes the next call to ReadRune to return the same rune. - UnreadRune() os.Error + UnreadRune() error // SkipSpace skips space in the input. Newlines are treated as space // unless the scan operation is Scanln, Fscanln or Sscanln, in which case // a newline is treated as EOF. @@ -47,14 +48,14 @@ type ScanState interface { // EOF. The returned slice points to shared data that may be overwritten // by the next call to Token, a call to a Scan function using the ScanState // as input, or when the calling Scan method returns. - Token(skipSpace bool, f func(int) bool) (token []byte, err os.Error) + Token(skipSpace bool, f func(rune) bool) (token []byte, err error) // Width returns the value of the width option and whether it has been set. // The unit is Unicode code points. Width() (wid int, ok bool) // Because ReadRune is implemented by the interface, Read should never be // called by the scanning routines and a valid implementation of // ScanState may choose always to return an error from Read. - Read(buf []byte) (n int, err os.Error) + Read(buf []byte) (n int, err error) } // Scanner is implemented by any value that has a Scan method, which scans @@ -62,27 +63,27 @@ type ScanState interface { // receiver, which must be a pointer to be useful. The Scan method is called // for any argument to Scan, Scanf, or Scanln that implements it. type Scanner interface { - Scan(state ScanState, verb int) os.Error + Scan(state ScanState, verb rune) error } // Scan scans text read from standard input, storing successive // space-separated values into successive arguments. Newlines count // as space. It returns the number of items successfully scanned. // If that is less than the number of arguments, err will report why. -func Scan(a ...interface{}) (n int, err os.Error) { +func Scan(a ...interface{}) (n int, err error) { return Fscan(os.Stdin, a...) } // Scanln is similar to Scan, but stops scanning at a newline and // after the final item there must be a newline or EOF. -func Scanln(a ...interface{}) (n int, err os.Error) { +func Scanln(a ...interface{}) (n int, err error) { return Fscanln(os.Stdin, a...) } // Scanf scans text read from standard input, storing successive // space-separated values into successive arguments as determined by // the format. It returns the number of items successfully scanned. -func Scanf(format string, a ...interface{}) (n int, err os.Error) { +func Scanf(format string, a ...interface{}) (n int, err error) { return Fscanf(os.Stdin, format, a...) } @@ -90,20 +91,20 @@ func Scanf(format string, a ...interface{}) (n int, err os.Error) { // values into successive arguments. Newlines count as space. It // returns the number of items successfully scanned. If that is less // than the number of arguments, err will report why. -func Sscan(str string, a ...interface{}) (n int, err os.Error) { +func Sscan(str string, a ...interface{}) (n int, err error) { return Fscan(strings.NewReader(str), a...) } // Sscanln is similar to Sscan, but stops scanning at a newline and // after the final item there must be a newline or EOF. -func Sscanln(str string, a ...interface{}) (n int, err os.Error) { +func Sscanln(str string, a ...interface{}) (n int, err error) { return Fscanln(strings.NewReader(str), a...) } // Sscanf scans the argument string, storing successive space-separated // values into successive arguments as determined by the format. It // returns the number of items successfully parsed. -func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) { +func Sscanf(str string, format string, a ...interface{}) (n int, err error) { return Fscanf(strings.NewReader(str), format, a...) } @@ -111,7 +112,7 @@ func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) { // values into successive arguments. Newlines count as space. It // returns the number of items successfully scanned. If that is less // than the number of arguments, err will report why. -func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) { +func Fscan(r io.Reader, a ...interface{}) (n int, err error) { s, old := newScanState(r, true, false) n, err = s.doScan(a) s.free(old) @@ -120,7 +121,7 @@ func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) { // Fscanln is similar to Fscan, but stops scanning at a newline and // after the final item there must be a newline or EOF. -func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) { +func Fscanln(r io.Reader, a ...interface{}) (n int, err error) { s, old := newScanState(r, false, true) n, err = s.doScan(a) s.free(old) @@ -130,7 +131,7 @@ func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) { // Fscanf scans text read from r, storing successive space-separated // values into successive arguments as determined by the format. It // returns the number of items successfully parsed. -func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) { +func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) { s, old := newScanState(r, false, false) n, err = s.doScanf(format, a) s.free(old) @@ -140,7 +141,7 @@ func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) // scanError represents an error generated by the scanning software. // It's used as a unique signature to identify such errors when recovering. type scanError struct { - err os.Error + err error } const eof = -1 @@ -149,8 +150,8 @@ const eof = -1 type ss struct { rr io.RuneReader // where to read input buf bytes.Buffer // token accumulator - peekRune int // one-rune lookahead - prevRune int // last rune returned by ReadRune + peekRune rune // one-rune lookahead + prevRune rune // last rune returned by ReadRune count int // runes consumed so far. atEOF bool // already read EOF ssave @@ -170,29 +171,29 @@ type ssave struct { // The Read method is only in ScanState so that ScanState // satisfies io.Reader. It will never be called when used as // intended, so there is no need to make it actually work. -func (s *ss) Read(buf []byte) (n int, err os.Error) { - return 0, os.NewError("ScanState's Read should not be called. Use ReadRune") +func (s *ss) Read(buf []byte) (n int, err error) { + return 0, errors.New("ScanState's Read should not be called. Use ReadRune") } -func (s *ss) ReadRune() (rune int, size int, err os.Error) { +func (s *ss) ReadRune() (r rune, size int, err error) { if s.peekRune >= 0 { s.count++ - rune = s.peekRune - size = utf8.RuneLen(rune) - s.prevRune = rune + r = s.peekRune + size = utf8.RuneLen(r) + s.prevRune = r s.peekRune = -1 return } if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.fieldLimit { - err = os.EOF + err = io.EOF return } - rune, size, err = s.rr.ReadRune() + r, size, err = s.rr.ReadRune() if err == nil { s.count++ - s.prevRune = rune - } else if err == os.EOF { + s.prevRune = r + } else if err == io.EOF { s.atEOF = true } return @@ -207,10 +208,10 @@ func (s *ss) Width() (wid int, ok bool) { // The public method returns an error; this private one panics. // If getRune reaches EOF, the return value is EOF (-1). -func (s *ss) getRune() (rune int) { - rune, _, err := s.ReadRune() +func (s *ss) getRune() (r rune) { + r, _, err := s.ReadRune() if err != nil { - if err == os.EOF { + if err == io.EOF { return eof } s.error(err) @@ -218,18 +219,18 @@ func (s *ss) getRune() (rune int) { return } -// mustReadRune turns os.EOF into a panic(io.ErrUnexpectedEOF). +// mustReadRune turns io.EOF into a panic(io.ErrUnexpectedEOF). // It is called in cases such as string scanning where an EOF is a // syntax error. -func (s *ss) mustReadRune() (rune int) { - rune = s.getRune() - if rune == eof { +func (s *ss) mustReadRune() (r rune) { + r = s.getRune() + if r == eof { s.error(io.ErrUnexpectedEOF) } return } -func (s *ss) UnreadRune() os.Error { +func (s *ss) UnreadRune() error { if u, ok := s.rr.(runeUnreader); ok { u.UnreadRune() } else { @@ -240,15 +241,15 @@ func (s *ss) UnreadRune() os.Error { return nil } -func (s *ss) error(err os.Error) { +func (s *ss) error(err error) { panic(scanError{err}) } func (s *ss) errorString(err string) { - panic(scanError{os.NewError(err)}) + panic(scanError{errors.New(err)}) } -func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) { +func (s *ss) Token(skipSpace bool, f func(rune) bool) (tok []byte, err error) { defer func() { if e := recover(); e != nil { if se, ok := e.(scanError); ok { @@ -267,7 +268,7 @@ func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) } // notSpace is the default scanning function used in Token. -func notSpace(r int) bool { +func notSpace(r rune) bool { return !unicode.IsSpace(r) } @@ -289,7 +290,7 @@ type readRune struct { // readByte returns the next byte from the input, which may be // left over from a previous read if the UTF-8 was ill-formed. -func (r *readRune) readByte() (b byte, err os.Error) { +func (r *readRune) readByte() (b byte, err error) { if r.pending > 0 { b = r.pendBuf[0] copy(r.pendBuf[0:], r.pendBuf[1:]) @@ -308,27 +309,27 @@ func (r *readRune) unread(buf []byte) { // ReadRune returns the next UTF-8 encoded code point from the // io.Reader inside r. -func (r *readRune) ReadRune() (rune int, size int, err os.Error) { +func (r *readRune) ReadRune() (rr rune, size int, err error) { r.buf[0], err = r.readByte() if err != nil { return 0, 0, err } if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case - rune = int(r.buf[0]) + rr = rune(r.buf[0]) return } var n int for n = 1; !utf8.FullRune(r.buf[0:n]); n++ { r.buf[n], err = r.readByte() if err != nil { - if err == os.EOF { + if err == io.EOF { err = nil break } return } } - rune, size = utf8.DecodeRune(r.buf[0:n]) + rr, size = utf8.DecodeRune(r.buf[0:n]) if size < n { // an error r.unread(r.buf[size:n]) } @@ -387,11 +388,11 @@ func (s *ss) free(old ssave) { // skipSpace skips spaces and maybe newlines. func (s *ss) skipSpace(stopAtNewline bool) { for { - rune := s.getRune() - if rune == eof { + r := s.getRune() + if r == eof { return } - if rune == '\n' { + if r == '\n' { if stopAtNewline { break } @@ -401,7 +402,7 @@ func (s *ss) skipSpace(stopAtNewline bool) { s.errorString("unexpected newline") return } - if !unicode.IsSpace(rune) { + if !unicode.IsSpace(r) { s.UnreadRune() break } @@ -411,21 +412,21 @@ func (s *ss) skipSpace(stopAtNewline bool) { // token returns the next space-delimited string from the input. It // skips white space. For Scanln, it stops at newlines. For Scan, // newlines are treated as spaces. -func (s *ss) token(skipSpace bool, f func(int) bool) []byte { +func (s *ss) token(skipSpace bool, f func(rune) bool) []byte { if skipSpace { s.skipSpace(false) } // read until white space or newline for { - rune := s.getRune() - if rune == eof { + r := s.getRune() + if r == eof { break } - if !f(rune) { + if !f(r) { s.UnreadRune() break } - s.buf.WriteRune(rune) + s.buf.WriteRune(r) } return s.buf.Bytes() } @@ -435,23 +436,23 @@ func (s *ss) typeError(field interface{}, expected string) { s.errorString("expected field of type pointer to " + expected + "; found " + reflect.TypeOf(field).String()) } -var complexError = os.NewError("syntax error scanning complex number") -var boolError = os.NewError("syntax error scanning boolean") +var complexError = errors.New("syntax error scanning complex number") +var boolError = errors.New("syntax error scanning boolean") // consume reads the next rune in the input and reports whether it is in the ok string. // If accept is true, it puts the character into the input token. func (s *ss) consume(ok string, accept bool) bool { - rune := s.getRune() - if rune == eof { + r := s.getRune() + if r == eof { return false } - if strings.IndexRune(ok, rune) >= 0 { + if strings.IndexRune(ok, r) >= 0 { if accept { - s.buf.WriteRune(rune) + s.buf.WriteRune(r) } return true } - if rune != eof && accept { + if r != eof && accept { s.UnreadRune() } return false @@ -459,17 +460,17 @@ func (s *ss) consume(ok string, accept bool) bool { // peek reports whether the next character is in the ok string, without consuming it. func (s *ss) peek(ok string) bool { - rune := s.getRune() - if rune != eof { + r := s.getRune() + if r != eof { s.UnreadRune() } - return strings.IndexRune(ok, rune) >= 0 + return strings.IndexRune(ok, r) >= 0 } func (s *ss) notEOF() { // Guarantee there is data to be read. - if rune := s.getRune(); rune == eof { - panic(os.EOF) + if r := s.getRune(); r == eof { + panic(io.EOF) } s.UnreadRune() } @@ -481,7 +482,7 @@ func (s *ss) accept(ok string) bool { } // okVerb verifies that the verb is present in the list, setting s.err appropriately if not. -func (s *ss) okVerb(verb int, okVerbs, typ string) bool { +func (s *ss) okVerb(verb rune, okVerbs, typ string) bool { for _, v := range okVerbs { if v == verb { return true @@ -492,7 +493,7 @@ func (s *ss) okVerb(verb int, okVerbs, typ string) bool { } // scanBool returns the value of the boolean represented by the next token. -func (s *ss) scanBool(verb int) bool { +func (s *ss) scanBool(verb rune) bool { s.skipSpace(false) s.notEOF() if !s.okVerb(verb, "tv", "boolean") { @@ -530,7 +531,7 @@ const ( ) // getBase returns the numeric base represented by the verb and its digit string. -func (s *ss) getBase(verb int) (base int, digits string) { +func (s *ss) getBase(verb rune) (base int, digits string) { s.okVerb(verb, "bdoUxXv", "integer") // sets s.err base = 10 digits = decimalDigits @@ -564,13 +565,13 @@ func (s *ss) scanNumber(digits string, haveDigits bool) string { // scanRune returns the next rune value in the input. func (s *ss) scanRune(bitSize int) int64 { s.notEOF() - rune := int64(s.getRune()) + r := int64(s.getRune()) n := uint(bitSize) - x := (rune << (64 - n)) >> (64 - n) - if x != rune { - s.errorString("overflow on character value " + string(rune)) + x := (r << (64 - n)) >> (64 - n) + if x != r { + s.errorString("overflow on character value " + string(r)) } - return rune + return r } // scanBasePrefix reports whether the integer begins with a 0 or 0x, @@ -593,7 +594,7 @@ func (s *ss) scanBasePrefix() (base int, digits string, found bool) { // scanInt returns the value of the integer represented by the next // token, checking for overflow. Any error is stored in s.err. -func (s *ss) scanInt(verb int, bitSize int) int64 { +func (s *ss) scanInt(verb rune, bitSize int) int64 { if verb == 'c' { return s.scanRune(bitSize) } @@ -612,7 +613,7 @@ func (s *ss) scanInt(verb int, bitSize int) int64 { } } tok := s.scanNumber(digits, haveDigits) - i, err := strconv.Btoi64(tok, base) + i, err := strconv.ParseInt(tok, base, 64) if err != nil { s.error(err) } @@ -626,7 +627,7 @@ func (s *ss) scanInt(verb int, bitSize int) int64 { // scanUint returns the value of the unsigned integer represented // by the next token, checking for overflow. Any error is stored in s.err. -func (s *ss) scanUint(verb int, bitSize int) uint64 { +func (s *ss) scanUint(verb rune, bitSize int) uint64 { if verb == 'c' { return uint64(s.scanRune(bitSize)) } @@ -642,7 +643,7 @@ func (s *ss) scanUint(verb int, bitSize int) uint64 { base, digits, haveDigits = s.scanBasePrefix() } tok := s.scanNumber(digits, haveDigits) - i, err := strconv.Btoui64(tok, base) + i, err := strconv.ParseUint(tok, base, 64) if err != nil { s.error(err) } @@ -718,7 +719,7 @@ func (s *ss) convertFloat(str string, n int) float64 { if p := strings.Index(str, "p"); p >= 0 { // Atof doesn't handle power-of-2 exponents, // but they're easy to evaluate. - f, err := strconv.AtofN(str[:p], n) + f, err := strconv.ParseFloat(str[:p], n) if err != nil { // Put full string into error. if e, ok := err.(*strconv.NumError); ok { @@ -736,7 +737,7 @@ func (s *ss) convertFloat(str string, n int) float64 { } return math.Ldexp(f, n) } - f, err := strconv.AtofN(str, n) + f, err := strconv.ParseFloat(str, n) if err != nil { s.error(err) } @@ -747,7 +748,7 @@ func (s *ss) convertFloat(str string, n int) float64 { // The atof argument is a type-specific reader for the underlying type. // If we're reading complex64, atof will parse float32s and convert them // to float64's to avoid reproducing this code for each complex type. -func (s *ss) scanComplex(verb int, n int) complex128 { +func (s *ss) scanComplex(verb rune, n int) complex128 { if !s.okVerb(verb, floatVerbs, "complex") { return 0 } @@ -761,7 +762,7 @@ func (s *ss) scanComplex(verb int, n int) complex128 { // convertString returns the string represented by the next input characters. // The format of the input is determined by the verb. -func (s *ss) convertString(verb int) (str string) { +func (s *ss) convertString(verb rune) (str string) { if !s.okVerb(verb, "svqx", "string") { return "" } @@ -786,26 +787,26 @@ func (s *ss) quotedString() string { case '`': // Back-quoted: Anything goes until EOF or back quote. for { - rune := s.mustReadRune() - if rune == quote { + r := s.mustReadRune() + if r == quote { break } - s.buf.WriteRune(rune) + s.buf.WriteRune(r) } return s.buf.String() case '"': // Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes. s.buf.WriteRune(quote) for { - rune := s.mustReadRune() - s.buf.WriteRune(rune) - if rune == '\\' { + r := s.mustReadRune() + s.buf.WriteRune(r) + if r == '\\' { // In a legal backslash escape, no matter how long, only the character // immediately after the escape can itself be a backslash or quote. // Thus we only need to protect the first character after the backslash. - rune := s.mustReadRune() - s.buf.WriteRune(rune) - } else if rune == '"' { + r := s.mustReadRune() + s.buf.WriteRune(r) + } else if r == '"' { break } } @@ -821,7 +822,8 @@ func (s *ss) quotedString() string { } // hexDigit returns the value of the hexadecimal digit -func (s *ss) hexDigit(digit int) int { +func (s *ss) hexDigit(d rune) int { + digit := int(d) switch digit { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': return digit - '0' @@ -871,14 +873,14 @@ const floatVerbs = "beEfFgGv" const hugeWid = 1 << 30 // scanOne scans a single value, deriving the scanner from the type of the argument. -func (s *ss) scanOne(verb int, field interface{}) { +func (s *ss) scanOne(verb rune, field interface{}) { s.buf.Reset() - var err os.Error + var err error // If the parameter has its own Scan method, use that. if v, ok := field.(Scanner); ok { err = v.Scan(s, verb) if err != nil { - if err == os.EOF { + if err == io.EOF { err = io.ErrUnexpectedEOF } s.error(err) @@ -975,11 +977,11 @@ func (s *ss) scanOne(verb int, field interface{}) { } // errorHandler turns local panics into error returns. -func errorHandler(errp *os.Error) { +func errorHandler(errp *error) { if e := recover(); e != nil { if se, ok := e.(scanError); ok { // catch local error *errp = se.err - } else if eof, ok := e.(os.Error); ok && eof == os.EOF { // out of input + } else if eof, ok := e.(error); ok && eof == io.EOF { // out of input *errp = eof } else { panic(e) @@ -988,7 +990,7 @@ func errorHandler(errp *os.Error) { } // doScan does the real work for scanning without a format string. -func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) { +func (s *ss) doScan(a []interface{}) (numProcessed int, err error) { defer errorHandler(&err) for _, field := range a { s.scanOne('v', field) @@ -997,11 +999,11 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) { // Check for newline if required. if !s.nlIsSpace { for { - rune := s.getRune() - if rune == '\n' || rune == eof { + r := s.getRune() + if r == '\n' || r == eof { break } - if !unicode.IsSpace(rune) { + if !unicode.IsSpace(r) { s.errorString("Scan: expected newline") break } @@ -1060,7 +1062,7 @@ func (s *ss) advance(format string) (i int) { // doScanf does the real work when scanning with a format string. // At the moment, it handles only pointers to basic types. -func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.Error) { +func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err error) { defer errorHandler(&err) end := len(format) - 1 // We process one item per non-trivial format diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go index 3f06e5725..b26c828cb 100644 --- a/src/pkg/fmt/scan_test.go +++ b/src/pkg/fmt/scan_test.go @@ -7,15 +7,15 @@ package fmt_test import ( "bufio" "bytes" + "errors" . "fmt" "io" "math" - "os" "reflect" "regexp" "strings" "testing" - "utf8" + "unicode/utf8" ) type ScanTest struct { @@ -56,6 +56,7 @@ var ( stringVal string stringVal1 string bytesVal []byte + runeVal rune complex64Val complex64 complex128Val complex128 renamedBoolVal renamedBool @@ -87,14 +88,14 @@ type FloatTest struct { // Xs accepts any non-empty run of the verb character type Xs string -func (x *Xs) Scan(state ScanState, verb int) os.Error { - tok, err := state.Token(true, func(r int) bool { return r == verb }) +func (x *Xs) Scan(state ScanState, verb rune) error { + tok, err := state.Token(true, func(r rune) bool { return r == verb }) if err != nil { return err } s := string(tok) if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(s) { - return os.NewError("syntax error for xs") + return errors.New("syntax error for xs") } *x = Xs(s) return nil @@ -109,7 +110,7 @@ type IntString struct { s string } -func (s *IntString) Scan(state ScanState, verb int) os.Error { +func (s *IntString) Scan(state ScanState, verb rune) error { if _, err := Fscan(state, &s.i); err != nil { return err } @@ -130,7 +131,7 @@ type myStringReader struct { r *strings.Reader } -func (s *myStringReader) Read(p []byte) (n int, err os.Error) { +func (s *myStringReader) Read(p []byte) (n int, err error) { return s.r.Read(p) } @@ -225,9 +226,9 @@ var scanfTests = []ScanfTest{ {"%v", "0377\n", &intVal, 0377}, {"%v", "0x44\n", &intVal, 0x44}, {"%d", "72\n", &intVal, 72}, - {"%c", "a\n", &intVal, 'a'}, - {"%c", "\u5072\n", &intVal, 0x5072}, - {"%c", "\u1234\n", &intVal, '\u1234'}, + {"%c", "a\n", &runeVal, 'a'}, + {"%c", "\u5072\n", &runeVal, '\u5072'}, + {"%c", "\u1234\n", &runeVal, '\u1234'}, {"%d", "73\n", &int8Val, int8(73)}, {"%d", "+74\n", &int16Val, int16(74)}, {"%d", "75\n", &int32Val, int32(75)}, @@ -322,9 +323,10 @@ var s, t string var c complex128 var x, y Xs var z IntString +var r1, r2, r3 rune var multiTests = []ScanfMultiTest{ - {"", "", nil, nil, ""}, + {"", "", []interface{}{}, []interface{}{}, ""}, {"%d", "23", args(&i), args(23), ""}, {"%2s%3s", "22333", args(&s, &t), args("22", "333"), ""}, {"%2d%3d", "44555", args(&i, &j), args(44, 555), ""}, @@ -333,7 +335,7 @@ var multiTests = []ScanfMultiTest{ {"%3d22%3d", "33322333", args(&i, &j), args(333, 333), ""}, {"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), 2.5), ""}, {"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""}, - {"%c%c%c", "2\u50c2X", args(&i, &j, &k), args('2', '\u50c2', 'X'), ""}, + {"%c%c%c", "2\u50c2X", args(&r1, &r2, &r3), args('2', '\u50c2', 'X'), ""}, // Custom scanners. {"%e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""}, @@ -347,10 +349,10 @@ var multiTests = []ScanfMultiTest{ {"X%d", "10X", args(&intVal), nil, "input does not match format"}, // Bad UTF-8: should see every byte. - {"%c%c%c", "\xc2X\xc2", args(&i, &j, &k), args(utf8.RuneError, 'X', utf8.RuneError), ""}, + {"%c%c%c", "\xc2X\xc2", args(&r1, &r2, &r3), args(utf8.RuneError, 'X', utf8.RuneError), ""}, } -func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, os.Error)) { +func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, error)) { for _, test := range scanTests { var r io.Reader if name == "StringReader" { @@ -378,7 +380,7 @@ func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{} } val := v.Interface() if !reflect.DeepEqual(val, test.out) { - t.Errorf("%s scanning %q: expected %v got %v, type %T", name, test.text, test.out, val, val) + t.Errorf("%s scanning %q: expected %#v got %#v, type %T", name, test.text, test.out, val, val) } } } @@ -417,7 +419,7 @@ func TestScanf(t *testing.T) { } val := v.Interface() if !reflect.DeepEqual(val, test.out) { - t.Errorf("scanning (%q, %q): expected %v got %v, type %T", test.format, test.text, test.out, val, val) + t.Errorf("scanning (%q, %q): expected %#v got %#v, type %T", test.format, test.text, test.out, val, val) } } } @@ -431,7 +433,7 @@ func TestScanOverflow(t *testing.T) { t.Errorf("expected overflow scanning %q", test.text) continue } - if !re.MatchString(err.String()) { + if !re.MatchString(err.Error()) { t.Errorf("expected overflow error scanning %q: %s", test.text, err) } } @@ -500,7 +502,7 @@ func testScanfMulti(name string, t *testing.T) { if err != nil { if test.err == "" { t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err) - } else if strings.Index(err.String(), test.err) < 0 { + } else if strings.Index(err.Error(), test.err) < 0 { t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err) } continue @@ -520,7 +522,7 @@ func testScanfMulti(name string, t *testing.T) { } result := resultVal.Interface() if !reflect.DeepEqual(result, test.out) { - t.Errorf("scanning (%q, %q): expected %v got %v", test.format, test.text, test.out, result) + t.Errorf("scanning (%q, %q): expected %#v got %#v", test.format, test.text, test.out, result) } } } @@ -594,7 +596,7 @@ func TestScanNotPointer(t *testing.T) { _, err := Fscan(r, a) if err == nil { t.Error("expected error scanning non-pointer") - } else if strings.Index(err.String(), "pointer") < 0 { + } else if strings.Index(err.Error(), "pointer") < 0 { t.Errorf("expected pointer error scanning non-pointer, got: %s", err) } } @@ -604,7 +606,7 @@ func TestScanlnNoNewline(t *testing.T) { _, err := Sscanln("1 x\n", &a) if err == nil { t.Error("expected error scanning string missing newline") - } else if strings.Index(err.String(), "newline") < 0 { + } else if strings.Index(err.Error(), "newline") < 0 { t.Errorf("expected newline error scanning string missing newline, got: %s", err) } } @@ -615,7 +617,7 @@ func TestScanlnWithMiddleNewline(t *testing.T) { _, err := Fscanln(r, &a, &b) if err == nil { t.Error("expected error scanning string with extra newline") - } else if strings.Index(err.String(), "newline") < 0 { + } else if strings.Index(err.Error(), "newline") < 0 { t.Errorf("expected newline error scanning string with extra newline, got: %s", err) } } @@ -626,7 +628,7 @@ type eofCounter struct { eofCount int } -func (ec *eofCounter) Read(b []byte) (n int, err os.Error) { +func (ec *eofCounter) Read(b []byte) (n int, err error) { n, err = ec.reader.Read(b) if n == 0 { ec.eofCount++ @@ -670,14 +672,14 @@ func TestEOFAtEndOfInput(t *testing.T) { if n != 1 || i != 23 { t.Errorf("Sscanf expected one value of 23; got %d %d", n, i) } - if err != os.EOF { + if err != io.EOF { t.Errorf("Sscanf expected EOF; got %q", err) } n, err = Sscan("234", &i, &j) if n != 1 || i != 234 { t.Errorf("Sscan expected one value of 234; got %d %d", n, i) } - if err != os.EOF { + if err != io.EOF { t.Errorf("Sscan expected EOF; got %q", err) } // Trailing space is tougher. @@ -685,7 +687,7 @@ func TestEOFAtEndOfInput(t *testing.T) { if n != 1 || i != 234 { t.Errorf("Sscan expected one value of 234; got %d %d", n, i) } - if err != os.EOF { + if err != io.EOF { t.Errorf("Sscan expected EOF; got %q", err) } } @@ -715,10 +717,10 @@ var eofTests = []struct { func TestEOFAllTypes(t *testing.T) { for i, test := range eofTests { - if _, err := Sscanf("", test.format, test.v); err != os.EOF { + if _, err := Sscanf("", test.format, test.v); err != io.EOF { t.Errorf("#%d: %s %T not eof on empty string: %s", i, test.format, test.v, err) } - if _, err := Sscanf(" ", test.format, test.v); err != os.EOF { + if _, err := Sscanf(" ", test.format, test.v); err != io.EOF { t.Errorf("#%d: %s %T not eof on trailing blanks: %s", i, test.format, test.v, err) } } @@ -749,8 +751,8 @@ type TwoLines string // Attempt to read two lines into the object. Scanln should prevent this // because it stops at newline; Scan and Scanf should be fine. -func (t *TwoLines) Scan(state ScanState, verb int) os.Error { - chars := make([]int, 0, 100) +func (t *TwoLines) Scan(state ScanState, verb rune) error { + chars := make([]rune, 0, 100) for nlCount := 0; nlCount < 2; { c, _, err := state.ReadRune() if err != nil { @@ -812,7 +814,7 @@ type RecursiveInt struct { next *RecursiveInt } -func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) { +func (r *RecursiveInt) Scan(state ScanState, verb rune) (err error) { _, err = Fscan(state, &r.i) if err != nil { return @@ -820,7 +822,7 @@ func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) { next := new(RecursiveInt) _, err = Fscanf(state, ".%v", next) if err != nil { - if err == os.NewError("input does not match format") || err == io.ErrUnexpectedEOF { + if err == errors.New("input does not match format") || err == io.ErrUnexpectedEOF { err = nil } return @@ -832,16 +834,15 @@ func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) { // Perform the same scanning task as RecursiveInt.Scan // but without recurring through scanner, so we can compare // performance more directly. -func scanInts(r *RecursiveInt, b *bytes.Buffer) (err os.Error) { +func scanInts(r *RecursiveInt, b *bytes.Buffer) (err error) { r.next = nil _, err = Fscan(b, &r.i) if err != nil { return } - var c int - c, _, err = b.ReadRune() + c, _, err := b.ReadRune() if err != nil { - if err == os.EOF { + if err == io.EOF { err = nil } return @@ -868,7 +869,7 @@ func makeInts(n int) []byte { func TestScanInts(t *testing.T) { testScanInts(t, scanInts) - testScanInts(t, func(r *RecursiveInt, b *bytes.Buffer) (err os.Error) { + testScanInts(t, func(r *RecursiveInt, b *bytes.Buffer) (err error) { _, err = Fscan(b, r) return }) @@ -878,7 +879,7 @@ func TestScanInts(t *testing.T) { // platform that does not support split stack. const intCount = 800 -func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) os.Error) { +func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) error) { r := new(RecursiveInt) ints := makeInts(intCount) buf := bytes.NewBuffer(ints) |