diff options
author | Ian Lance Taylor <iant@google.com> | 2015-01-15 00:27:56 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-01-15 00:27:56 +0000 |
commit | f8d9fa9e80b57f89e7877ce6cad8a3464879009b (patch) | |
tree | 58a1724fee16d2b03c65678c4dd9b50bb97137a9 /libgo/go/fmt | |
parent | 6bd3f109d8d8fa58eeccd6b3504721b4f20c00c2 (diff) | |
download | gcc-f8d9fa9e80b57f89e7877ce6cad8a3464879009b.zip gcc-f8d9fa9e80b57f89e7877ce6cad8a3464879009b.tar.gz gcc-f8d9fa9e80b57f89e7877ce6cad8a3464879009b.tar.bz2 |
libgo, compiler: Upgrade libgo to Go 1.4, except for runtime.
This upgrades all of libgo other than the runtime package to
the Go 1.4 release. In Go 1.4 much of the runtime was
rewritten into Go. Merging that code will take more time and
will not change the API, so I'm putting it off for now.
There are a few runtime changes anyhow, to accomodate other
packages that rely on minor modifications to the runtime
support.
The compiler changes slightly to add a one-bit flag to each
type descriptor kind that is stored directly in an interface,
which for gccgo is currently only pointer types. Another
one-bit flag (gcprog) is reserved because it is used by the gc
compiler, but gccgo does not currently use it.
There is another error check in the compiler since I ran
across it during testing.
gotools/:
* Makefile.am (go_cmd_go_files): Sort entries. Add generate.go.
* Makefile.in: Rebuild.
From-SVN: r219627
Diffstat (limited to 'libgo/go/fmt')
-rw-r--r-- | libgo/go/fmt/doc.go | 47 | ||||
-rw-r--r-- | libgo/go/fmt/fmt_test.go | 197 | ||||
-rw-r--r-- | libgo/go/fmt/format.go | 84 | ||||
-rw-r--r-- | libgo/go/fmt/print.go | 226 | ||||
-rw-r--r-- | libgo/go/fmt/scan.go | 1 | ||||
-rw-r--r-- | libgo/go/fmt/scan_test.go | 32 |
6 files changed, 431 insertions, 156 deletions
diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go index 02642d6..ee54463 100644 --- a/libgo/go/fmt/doc.go +++ b/libgo/go/fmt/doc.go @@ -13,7 +13,7 @@ The verbs: General: - %v the value in a default format. + %v the value in a default format when printing structs, the plus flag (%+v) adds field names %#v a Go-syntax representation of the value %T a Go-syntax representation of the type of the value @@ -38,8 +38,8 @@ %E scientific notation, e.g. -1234.456E+78 %f decimal point but no exponent, e.g. 123.456 %F synonym for %f - %g whichever of %e or %f produces more compact output - %G whichever of %E or %f produces more compact output + %g %e for large exponents, %f otherwise + %G %E for large exponents, %F otherwise String and slice of bytes: %s the uninterpreted bytes of the string or slice %q a double-quoted string safely escaped with Go syntax @@ -51,6 +51,21 @@ There is no 'u' flag. Integers are printed unsigned if they have unsigned type. Similarly, there is no need to specify the size of the operand (int8, int64). + The default format for %v is: + bool: %t + int, int8 etc.: %d + uint, uint8 etc.: %d, %x if printed with %#v + float32, complex64, etc: %g + string: %s + chan: %p + pointer: %p + For compound objects, the elements are printed using these rules, recursively, + laid out like this: + struct: {field0 field1 ...} + array, slice: [elem0 elem1 ...] + maps: map[key1:value1 key2:value2] + pointer to above: &{}, &[], &map[] + Width is specified by an optional decimal number immediately following the verb. If absent, the width is whatever is necessary to represent the value. Precision is specified after the (optional) width by a period followed by a @@ -63,16 +78,20 @@ %9.2f width 9, precision 2 %9.f width 9, precision 0 - Width and precision are measured in units of Unicode code points. - (This differs from C's printf where the units are numbers - of bytes.) Either or both of the flags may be replaced with the - character '*', causing their values to be obtained from the next - operand, which must be of type int. + Width and precision are measured in units of Unicode code points, + that is, runes. (This differs from C's printf where the + units are always measured in bytes.) Either or both of the flags + may be replaced with the character '*', causing their values to be + obtained from the next operand, which must be of type int. - For most values, width is the minimum number of characters to output, + For most values, width is the minimum number of runes to output, padding the formatted form with spaces if necessary. - For strings, precision is the maximum number of characters to output, - truncating if necessary. + + For strings, byte slices and byte arrays, however, precision + limits the length of the input to be formatted (not the size of + the output), truncating if necessary. Normally it is measured in + runes, but for these types when formatted with the %x or %X format + it is measured in bytes. For floating-point values, width sets the minimum width of the field and precision sets the number of places after the decimal, if appropriate, @@ -147,6 +166,10 @@ func (x X) String() string { return Sprintf("<%s>", x) } convert the value before recurring: func (x X) String() string { return Sprintf("<%s>", string(x)) } + Infinite recursion can also be triggered by self-referential data + structures, such as a slice that contains itself as an element, if + that type has a String method. Such pathologies are rare, however, + and the package does not protect against them. Explicit argument indexes: @@ -160,7 +183,7 @@ For example, fmt.Sprintf("%[2]d %[1]d\n", 11, 22) - will yield "22, 11", while + will yield "22 11", while fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6), equivalent to fmt.Sprintf("%6.2f", 12.0), diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go index 8e69231..ccd8090 100644 --- a/libgo/go/fmt/fmt_test.go +++ b/libgo/go/fmt/fmt_test.go @@ -108,6 +108,20 @@ func (p *P) String() string { var barray = [5]renamedUint8{1, 2, 3, 4, 5} var bslice = barray[:] +type byteStringer byte + +func (byteStringer) String() string { return "X" } + +var byteStringerSlice = []byteStringer{97, 98, 99, 100} + +type byteFormatter byte + +func (byteFormatter) Format(f State, _ rune) { + Fprint(f, "X") +} + +var byteFormatterSlice = []byteFormatter{97, 98, 99, 100} + var b byte var fmtTests = []struct { @@ -125,13 +139,17 @@ var fmtTests = []struct { {"%x", "xyz", "78797a"}, {"%X", "xyz", "78797A"}, {"%q", "abc", `"abc"`}, + {"%#x", []byte("abc\xff"), "0x616263ff"}, + {"%#X", []byte("abc\xff"), "0X616263FF"}, + {"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"}, + {"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"}, // basic bytes {"%s", []byte("abc"), "abc"}, {"%x", []byte("abc"), "616263"}, {"% x", []byte("abc\xff"), "61 62 63 ff"}, - {"%#x", []byte("abc\xff"), "0x610x620x630xff"}, - {"%#X", []byte("abc\xff"), "0X610X620X630XFF"}, + {"%#x", []byte("abc\xff"), "0x616263ff"}, + {"%#X", []byte("abc\xff"), "0X616263FF"}, {"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"}, {"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"}, {"% X", []byte("abc\xff"), "61 62 63 FF"}, @@ -176,9 +194,18 @@ var fmtTests = []struct { {"%.5s", "日本語日本語", "日本語日本"}, {"%.5s", []byte("日本語日本語"), "日本語日本"}, {"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`}, + {"%.5x", "abcdefghijklmnopqrstuvwxyz", `6162636465`}, + {"%.5q", []byte("abcdefghijklmnopqrstuvwxyz"), `"abcde"`}, + {"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), `6162636465`}, {"%.3q", "日本語日本語", `"日本語"`}, {"%.3q", []byte("日本語日本語"), `"日本語"`}, + {"%.1q", "日本語", `"日"`}, + {"%.1q", []byte("日本語"), `"日"`}, + {"%.1x", "日本語", `e6`}, + {"%.1X", []byte("日本語"), `E6`}, {"%10.1q", "日本語日本語", ` "日"`}, + {"%3c", '⌘', " ⌘"}, + {"%5q", '\u2026', ` '…'`}, {"%10v", nil, " <nil>"}, {"%-10v", nil, "<nil> "}, @@ -379,7 +406,7 @@ var fmtTests = []struct { {"%s", I(23), `<23>`}, {"%q", I(23), `"<23>"`}, {"%x", I(23), `3c32333e`}, - {"%#x", I(23), `0x3c0x320x330x3e`}, + {"%#x", I(23), `0x3c32333e`}, {"%# x", I(23), `0x3c 0x32 0x33 0x3e`}, {"%d", I(23), `23`}, // Stringer applies only to string formats. @@ -623,6 +650,21 @@ var fmtTests = []struct { {"%+010.2f", -104.66 + 440.51i, "(-000104.66+000440.51i)"}, {"%+010.2f", +104.66 - 440.51i, "(+000104.66-000440.51i)"}, {"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"}, + + // []T where type T is a byte with a Stringer method. + {"%v", byteStringerSlice, "[X X X X]"}, + {"%s", byteStringerSlice, "abcd"}, + {"%q", byteStringerSlice, "\"abcd\""}, + {"%x", byteStringerSlice, "61626364"}, + {"%#v", byteStringerSlice, "[]fmt_test.byteStringer{0x61, 0x62, 0x63, 0x64}"}, + + // And the same for Formatter. + {"%v", byteFormatterSlice, "[X X X X]"}, + {"%s", byteFormatterSlice, "abcd"}, + {"%q", byteFormatterSlice, "\"abcd\""}, + {"%x", byteFormatterSlice, "61626364"}, + // This next case seems wrong, but the docs say the Formatter wins here. + {"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X}"}, } // zeroFill generates zero-filled strings of the specified width. The length @@ -672,7 +714,7 @@ func TestSprintf(t *testing.T) { // thing as if done by hand with two singleton prints. func TestComplexFormatting(t *testing.T) { var yesNo = []bool{true, false} - var signs = []float64{1, 0, -1} + var values = []float64{1, 0, -1, math.Inf(1), math.Inf(-1), math.NaN()} for _, plus := range yesNo { for _, zero := range yesNo { for _, space := range yesNo { @@ -697,10 +739,10 @@ func TestComplexFormatting(t *testing.T) { imagFmt += "+" imagFmt += "10.2" imagFmt += string(char) - for _, realSign := range signs { - for _, imagSign := range signs { - one := Sprintf(realFmt, complex(realSign, imagSign)) - two := Sprintf("("+realFmt+imagFmt+"i)", realSign, imagSign) + for _, realValue := range values { + for _, imagValue := range values { + one := Sprintf(realFmt, complex(realValue, imagValue)) + two := Sprintf("("+realFmt+imagFmt+"i)", realValue, imagValue) if one != two { t.Error(f, one, two) } @@ -819,7 +861,25 @@ func BenchmarkManyArgs(b *testing.B) { }) } +func BenchmarkFprintInt(b *testing.B) { + var buf bytes.Buffer + for i := 0; i < b.N; i++ { + buf.Reset() + Fprint(&buf, 123456) + } +} + +func BenchmarkFprintIntNoAlloc(b *testing.B) { + var x interface{} = 123456 + var buf bytes.Buffer + for i := 0; i < b.N; i++ { + buf.Reset() + Fprint(&buf, x) + } +} + var mallocBuf bytes.Buffer +var mallocPointer *int // A pointer so we know the interface value won't allocate. // gccgo numbers are different because gccgo does not have escape // analysis yet. @@ -833,11 +893,13 @@ var mallocTest = []struct { {5, `Sprintf("%x")`, func() { Sprintf("%x", 7) }}, {5, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }}, {5, `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. - {20, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }}, - {5, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }}, + {20, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }}, // TODO: Can this be 1? {5, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }}, + // If the interface value doesn't need to allocate, amortized allocation overhead should be zero. + {5, `Fprintf(buf, "%x %x %x")`, func() { + mallocBuf.Reset() + Fprintf(&mallocBuf, "%x %x %x", mallocPointer, mallocPointer, mallocPointer) + }}, } var _ bytes.Buffer @@ -859,7 +921,7 @@ func TestCountMallocs(t *testing.T) { type flagPrinter struct{} -func (*flagPrinter) Format(f State, c rune) { +func (flagPrinter) Format(f State, c rune) { s := "%" for i := 0; i < 128; i++ { if f.Flag(i) { @@ -905,11 +967,12 @@ func TestFlagParser(t *testing.T) { } func TestStructPrinter(t *testing.T) { - var s struct { + type T struct { a string b string c int } + var s T s.a = "abc" s.b = "def" s.c = 123 @@ -919,15 +982,38 @@ func TestStructPrinter(t *testing.T) { }{ {"%v", "{abc def 123}"}, {"%+v", "{a:abc b:def c:123}"}, + {"%#v", `fmt_test.T{a:"abc", b:"def", c:123}`}, } for _, tt := range tests { out := Sprintf(tt.fmt, s) if out != tt.out { - t.Errorf("Sprintf(%q, &s) = %q, want %q", tt.fmt, out, tt.out) + t.Errorf("Sprintf(%q, s) = %#q, want %#q", tt.fmt, out, tt.out) + } + // The same but with a pointer. + out = Sprintf(tt.fmt, &s) + if out != "&"+tt.out { + t.Errorf("Sprintf(%q, &s) = %#q, want %#q", tt.fmt, out, "&"+tt.out) } } } +func TestSlicePrinter(t *testing.T) { + slice := []int{} + s := Sprint(slice) + if s != "[]" { + t.Errorf("empty slice printed as %q not %q", s, "[]") + } + slice = []int{1, 2, 3} + s = Sprint(slice) + if s != "[1 2 3]" { + t.Errorf("slice: got %q expected %q", s, "[1 2 3]") + } + s = Sprint(&slice) + if s != "&[1 2 3]" { + t.Errorf("&slice: got %q expected %q", s, "&[1 2 3]") + } +} + // presentInMap checks map printing using substrings so we don't depend on the // print order. func presentInMap(s string, a []string, t *testing.T) { @@ -954,6 +1040,12 @@ func TestMapPrinter(t *testing.T) { a := []string{"1:one", "2:two", "3:three"} presentInMap(Sprintf("%v", m1), a, t) presentInMap(Sprint(m1), a, t) + // Pointer to map prints the same but with initial &. + if !strings.HasPrefix(Sprint(&m1), "&") { + t.Errorf("no initial & for address of map") + } + presentInMap(Sprintf("%v", &m1), a, t) + presentInMap(Sprint(&m1), a, t) } func TestEmptyMap(t *testing.T) { @@ -1084,10 +1176,10 @@ var panictests = []struct { } func TestPanics(t *testing.T) { - for _, tt := range panictests { + for i, tt := range panictests { s := Sprintf(tt.fmt, tt.in) if s != tt.out { - t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out) + t.Errorf("%d: %q: got %q expected %q", i, tt.fmt, s, tt.out) } } } @@ -1147,3 +1239,74 @@ func TestNilDoesNotBecomeTyped(t *testing.T) { t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got) } } + +var formatterFlagTests = []struct { + in string + val interface{} + out string +}{ + // scalar values with the (unused by fmt) 'a' verb. + {"%a", flagPrinter{}, "[%a]"}, + {"%-a", flagPrinter{}, "[%-a]"}, + {"%+a", flagPrinter{}, "[%+a]"}, + {"%#a", flagPrinter{}, "[%#a]"}, + {"% a", flagPrinter{}, "[% a]"}, + {"%0a", flagPrinter{}, "[%0a]"}, + {"%1.2a", flagPrinter{}, "[%1.2a]"}, + {"%-1.2a", flagPrinter{}, "[%-1.2a]"}, + {"%+1.2a", flagPrinter{}, "[%+1.2a]"}, + {"%-+1.2a", flagPrinter{}, "[%+-1.2a]"}, + {"%-+1.2abc", flagPrinter{}, "[%+-1.2a]bc"}, + {"%-1.2abc", flagPrinter{}, "[%-1.2a]bc"}, + + // composite values with the 'a' verb + {"%a", [1]flagPrinter{}, "[[%a]]"}, + {"%-a", [1]flagPrinter{}, "[[%-a]]"}, + {"%+a", [1]flagPrinter{}, "[[%+a]]"}, + {"%#a", [1]flagPrinter{}, "[[%#a]]"}, + {"% a", [1]flagPrinter{}, "[[% a]]"}, + {"%0a", [1]flagPrinter{}, "[[%0a]]"}, + {"%1.2a", [1]flagPrinter{}, "[[%1.2a]]"}, + {"%-1.2a", [1]flagPrinter{}, "[[%-1.2a]]"}, + {"%+1.2a", [1]flagPrinter{}, "[[%+1.2a]]"}, + {"%-+1.2a", [1]flagPrinter{}, "[[%+-1.2a]]"}, + {"%-+1.2abc", [1]flagPrinter{}, "[[%+-1.2a]]bc"}, + {"%-1.2abc", [1]flagPrinter{}, "[[%-1.2a]]bc"}, + + // simple values with the 'v' verb + {"%v", flagPrinter{}, "[%v]"}, + {"%-v", flagPrinter{}, "[%-v]"}, + {"%+v", flagPrinter{}, "[%+v]"}, + {"%#v", flagPrinter{}, "[%#v]"}, + {"% v", flagPrinter{}, "[% v]"}, + {"%0v", flagPrinter{}, "[%0v]"}, + {"%1.2v", flagPrinter{}, "[%1.2v]"}, + {"%-1.2v", flagPrinter{}, "[%-1.2v]"}, + {"%+1.2v", flagPrinter{}, "[%+1.2v]"}, + {"%-+1.2v", flagPrinter{}, "[%+-1.2v]"}, + {"%-+1.2vbc", flagPrinter{}, "[%+-1.2v]bc"}, + {"%-1.2vbc", flagPrinter{}, "[%-1.2v]bc"}, + + // composite values with the 'v' verb. + {"%v", [1]flagPrinter{}, "[[%v]]"}, + {"%-v", [1]flagPrinter{}, "[[%-v]]"}, + {"%+v", [1]flagPrinter{}, "[[%+v]]"}, + {"%#v", [1]flagPrinter{}, "[1]fmt_test.flagPrinter{[%#v]}"}, + {"% v", [1]flagPrinter{}, "[[% v]]"}, + {"%0v", [1]flagPrinter{}, "[[%0v]]"}, + {"%1.2v", [1]flagPrinter{}, "[[%1.2v]]"}, + {"%-1.2v", [1]flagPrinter{}, "[[%-1.2v]]"}, + {"%+1.2v", [1]flagPrinter{}, "[[%+1.2v]]"}, + {"%-+1.2v", [1]flagPrinter{}, "[[%+-1.2v]]"}, + {"%-+1.2vbc", [1]flagPrinter{}, "[[%+-1.2v]]bc"}, + {"%-1.2vbc", [1]flagPrinter{}, "[[%-1.2v]]bc"}, +} + +func TestFormatterFlags(t *testing.T) { + for _, tt := range formatterFlagTests { + s := Sprintf(tt.in, tt.val) + if s != tt.out { + t.Errorf("Sprintf(%q, %T) = %q, want %q", tt.in, tt.val, s, tt.out) + } + } +} diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go index a89c542..4d97d14 100644 --- a/libgo/go/fmt/format.go +++ b/libgo/go/fmt/format.go @@ -34,15 +34,8 @@ func init() { } } -// A fmt is the raw formatter used by Printf etc. -// It prints into a buffer that must be set up separately. -type fmt struct { - intbuf [nByte]byte - buf *buffer - // width, precision - wid int - prec int - // flags +// flags placed in a separate struct for easy clearing. +type fmtFlags struct { widPresent bool precPresent bool minus bool @@ -52,20 +45,27 @@ type fmt struct { unicode bool uniQuote bool // Use 'x'= prefix for %U if printable. zero bool + + // For the formats %+v %#v, we set the plusV/sharpV flags + // and clear the plus/sharp flags since %+v and %#v are in effect + // different, flagless formats set at the top level. + plusV bool + sharpV bool +} + +// A fmt is the raw formatter used by Printf etc. +// It prints into a buffer that must be set up separately. +type fmt struct { + intbuf [nByte]byte + buf *buffer + // width, precision + wid int + prec int + fmtFlags } func (f *fmt) clearflags() { - f.wid = 0 - f.widPresent = false - f.prec = 0 - f.precPresent = false - f.minus = false - f.plus = false - f.sharp = false - f.space = false - f.unicode = false - f.uniQuote = false - f.zero = false + f.fmtFlags = fmtFlags{} } func (f *fmt) init(buf *buffer) { @@ -114,7 +114,7 @@ func (f *fmt) pad(b []byte) { f.buf.Write(b) return } - padding, left, right := f.computePadding(len(b)) + padding, left, right := f.computePadding(utf8.RuneCount(b)) if left > 0 { f.writePadding(left, padding) } @@ -199,10 +199,36 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) { // block but it's not worth the duplication, so ua has 64 bits. i := len(buf) ua := uint64(a) - for ua >= base { - i-- - buf[i] = digits[ua%base] - ua /= base + // use constants for the division and modulo for more efficient code. + // switch cases ordered by popularity. + switch base { + case 10: + for ua >= 10 { + i-- + next := ua / 10 + buf[i] = byte('0' + ua - next*10) + ua = next + } + case 16: + for ua >= 16 { + i-- + buf[i] = digits[ua&0xF] + ua >>= 4 + } + case 8: + for ua >= 8 { + i-- + buf[i] = byte('0' + ua&7) + ua >>= 3 + } + case 2: + for ua >= 2 { + i-- + buf[i] = byte('0' + ua&1) + ua >>= 1 + } + default: + panic("fmt: unknown base; can't happen") } i-- buf[i] = digits[ua] @@ -298,7 +324,7 @@ func (f *fmt) fmt_sbx(s string, b []byte, digits string) { if i > 0 && f.space { buf = append(buf, ' ') } - if f.sharp { + if f.sharp && (f.space || i == 0) { buf = append(buf, '0', x) } var c byte @@ -314,11 +340,17 @@ func (f *fmt) fmt_sbx(s string, b []byte, digits string) { // fmt_sx formats a string as a hexadecimal encoding of its bytes. func (f *fmt) fmt_sx(s, digits string) { + if f.precPresent && f.prec < len(s) { + s = s[:f.prec] + } f.fmt_sbx(s, nil, digits) } // fmt_bx formats a byte slice as a hexadecimal encoding of its bytes. func (f *fmt) fmt_bx(b []byte, digits string) { + if f.precPresent && f.prec < len(b) { + b = b[:f.prec] + } f.fmt_sbx("", b, digits) } diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go index 302661f..59a30d2 100644 --- a/libgo/go/fmt/print.go +++ b/libgo/go/fmt/print.go @@ -128,7 +128,7 @@ var ppFree = sync.Pool{ New: func() interface{} { return new(pp) }, } -// newPrinter allocates a new pp struct or grab a cached one. +// newPrinter allocates a new pp struct or grabs a cached one. func newPrinter() *pp { p := ppFree.Get().(*pp) p.panicking = false @@ -297,13 +297,13 @@ func parsenum(s string, start, end int) (num int, isnum bool, newi int) { return } -func (p *pp) unknownType(v interface{}) { - if v == nil { +func (p *pp) unknownType(v reflect.Value) { + if !v.IsValid() { p.buf.Write(nilAngleBytes) return } p.buf.WriteByte('?') - p.buf.WriteString(reflect.TypeOf(v).String()) + p.buf.WriteString(v.Type().String()) p.buf.WriteByte('?') } @@ -317,11 +317,11 @@ func (p *pp) badVerb(verb rune) { case p.arg != nil: p.buf.WriteString(reflect.TypeOf(p.arg).String()) p.add('=') - p.printArg(p.arg, 'v', false, false, 0) + p.printArg(p.arg, 'v', 0) case p.value.IsValid(): p.buf.WriteString(p.value.Type().String()) p.add('=') - p.printValue(p.value, 'v', false, false, 0) + p.printValue(p.value, 'v', 0) default: p.buf.Write(nilAngleBytes) } @@ -406,7 +406,7 @@ func (p *pp) fmtUnicode(v int64) { p.fmt.sharp = sharp } -func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) { +func (p *pp) fmtUint64(v uint64, verb rune) { switch verb { case 'b': p.fmt.integer(int64(v), 2, unsigned, ldigits) @@ -415,7 +415,7 @@ func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) { case 'd': p.fmt.integer(int64(v), 10, unsigned, ldigits) case 'v': - if goSyntax { + if p.fmt.sharpV { p.fmt0x64(v, true) } else { p.fmt.integer(int64(v), 10, unsigned, ldigits) @@ -499,10 +499,10 @@ func (p *pp) fmtComplex128(v complex128, verb rune) { } } -func (p *pp) fmtString(v string, verb rune, goSyntax bool) { +func (p *pp) fmtString(v string, verb rune) { switch verb { case 'v': - if goSyntax { + if p.fmt.sharpV { p.fmt.fmt_q(v) } else { p.fmt.fmt_s(v) @@ -520,9 +520,9 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) { } } -func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, depth int) { +func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) { if verb == 'v' || verb == 'd' { - if goSyntax { + if p.fmt.sharpV { if v == nil { if typ == nil { p.buf.WriteString("[]byte(nil)") @@ -543,15 +543,15 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, dept } for i, c := range v { if i > 0 { - if goSyntax { + if p.fmt.sharpV { p.buf.Write(commaSpaceBytes) } else { p.buf.WriteByte(' ') } } - p.printArg(c, 'v', p.fmt.plus, goSyntax, depth+1) + p.printArg(c, 'v', depth+1) } - if goSyntax { + if p.fmt.sharpV { p.buf.WriteByte('}') } else { p.buf.WriteByte(']') @@ -572,7 +572,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, dept } } -func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) { +func (p *pp) fmtPointer(value reflect.Value, verb rune) { use0x64 := true switch verb { case 'p', 'v': @@ -594,7 +594,7 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) { return } - if goSyntax { + if p.fmt.sharpV { p.add('(') p.buf.WriteString(value.Type().String()) p.add(')') @@ -611,7 +611,7 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) { if use0x64 { p.fmt0x64(uint64(u), !p.fmt.sharp) } else { - p.fmtUint64(uint64(u), verb, false) + p.fmtUint64(uint64(u), verb) } } } @@ -636,42 +636,65 @@ func (p *pp) catchPanic(arg interface{}, verb rune) { // Nested panics; the recursion in printArg cannot succeed. panic(err) } + p.fmt.clearflags() // We are done, and for this output we want default behavior. p.buf.Write(percentBangBytes) p.add(verb) p.buf.Write(panicBytes) p.panicking = true - p.printArg(err, 'v', false, false, 0) + p.printArg(err, 'v', 0) p.panicking = false p.buf.WriteByte(')') } } -func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString, handled bool) { +// clearSpecialFlags pushes %#v back into the regular flags and returns their old state. +func (p *pp) clearSpecialFlags() (plusV, sharpV bool) { + plusV = p.fmt.plusV + if plusV { + p.fmt.plus = true + p.fmt.plusV = false + } + sharpV = p.fmt.sharpV + if sharpV { + p.fmt.sharp = true + p.fmt.sharpV = false + } + return +} + +// restoreSpecialFlags, whose argument should be a call to clearSpecialFlags, +// restores the setting of the plusV and sharpV flags. +func (p *pp) restoreSpecialFlags(plusV, sharpV bool) { + if plusV { + p.fmt.plus = false + p.fmt.plusV = true + } + if sharpV { + p.fmt.sharp = false + p.fmt.sharpV = true + } +} + +func (p *pp) handleMethods(verb rune, depth int) (handled bool) { if p.erroring { return } // Is it a Formatter? if formatter, ok := p.arg.(Formatter); ok { handled = true - wasString = false + defer p.restoreSpecialFlags(p.clearSpecialFlags()) defer p.catchPanic(p.arg, 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 argument knows how to supply it, take care of it now. - if goSyntax { - p.fmt.sharp = false + if p.fmt.sharpV { if stringer, ok := p.arg.(GoStringer); ok { - wasString = false handled = true defer p.catchPanic(p.arg, verb) // Print the result of GoString unadorned. - p.fmtString(stringer.GoString(), 's', false) + p.fmt.fmt_s(stringer.GoString()) return } } else { @@ -682,30 +705,27 @@ func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString 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, + // setting handled and deferring catchPanic // must happen before calling the method. switch v := p.arg.(type) { case error: - wasString = false handled = true defer p.catchPanic(p.arg, verb) - p.printArg(v.Error(), verb, plus, false, depth) + p.printArg(v.Error(), verb, depth) return case Stringer: - wasString = false handled = true defer p.catchPanic(p.arg, verb) - p.printArg(v.String(), verb, plus, false, depth) + p.printArg(v.String(), verb, depth) return } } } - handled = false - return + return false } -func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int) (wasString bool) { +func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) { p.arg = arg p.value = reflect.Value{} @@ -722,26 +742,13 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int // %T (the value's type) and %p (its address) are special; we always do them first. switch verb { case 'T': - p.printArg(reflect.TypeOf(arg).String(), 's', false, false, 0) + p.printArg(reflect.TypeOf(arg).String(), 's', 0) return false case 'p': - p.fmtPointer(reflect.ValueOf(arg), verb, goSyntax) + p.fmtPointer(reflect.ValueOf(arg), verb) return false } - // Clear flags for base formatters. - // handleMethods needs them, so we must restore them later. - // We could call handleMethods here and avoid this work, but - // handleMethods is expensive enough to be worth delaying. - oldPlus := p.fmt.plus - oldSharp := p.fmt.sharp - if plus { - p.fmt.plus = false - } - if goSyntax { - p.fmt.sharp = false - } - // Some types can be done without reflection. switch f := arg.(type) { case bool: @@ -765,40 +772,37 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int case int64: p.fmtInt64(f, verb) case uint: - p.fmtUint64(uint64(f), verb, goSyntax) + p.fmtUint64(uint64(f), verb) case uint8: - p.fmtUint64(uint64(f), verb, goSyntax) + p.fmtUint64(uint64(f), verb) case uint16: - p.fmtUint64(uint64(f), verb, goSyntax) + p.fmtUint64(uint64(f), verb) case uint32: - p.fmtUint64(uint64(f), verb, goSyntax) + p.fmtUint64(uint64(f), verb) case uint64: - p.fmtUint64(f, verb, goSyntax) + p.fmtUint64(f, verb) case uintptr: - p.fmtUint64(uint64(f), verb, goSyntax) + p.fmtUint64(uint64(f), verb) case string: - p.fmtString(f, verb, goSyntax) + p.fmtString(f, verb) wasString = verb == 's' || verb == 'v' case []byte: - p.fmtBytes(f, verb, goSyntax, nil, depth) + p.fmtBytes(f, verb, nil, depth) wasString = verb == 's' default: - // Restore flags in case handleMethods finds a Formatter. - p.fmt.plus = oldPlus - p.fmt.sharp = oldSharp // If the type is not simple, it might have methods. - if isString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled { - return isString + if handled := p.handleMethods(verb, depth); handled { + return false } // Need to use reflection - return p.printReflectValue(reflect.ValueOf(arg), verb, plus, goSyntax, depth) + return p.printReflectValue(reflect.ValueOf(arg), verb, depth) } p.arg = nil return } // printValue is like printArg 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) { +func (p *pp) printValue(value reflect.Value, verb rune, depth int) (wasString bool) { if !value.IsValid() { if verb == 'T' || verb == 'v' { p.buf.Write(nilAngleBytes) @@ -812,10 +816,10 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, dep // %T (the value's type) and %p (its address) are special; we always do them first. switch verb { case 'T': - p.printArg(value.Type().String(), 's', false, false, 0) + p.printArg(value.Type().String(), 's', 0) return false case 'p': - p.fmtPointer(value, verb, goSyntax) + p.fmtPointer(value, verb) return false } @@ -825,16 +829,18 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, dep if value.CanInterface() { p.arg = value.Interface() } - if isString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled { - return isString + if handled := p.handleMethods(verb, depth); handled { + return false } - return p.printReflectValue(value, verb, plus, goSyntax, depth) + return p.printReflectValue(value, verb, depth) } +var byteType = reflect.TypeOf(byte(0)) + // printReflectValue is the fallback for both printArg 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) { +func (p *pp) printReflectValue(value reflect.Value, verb rune, depth int) (wasString bool) { oldValue := p.value p.value = value BigSwitch: @@ -844,7 +850,7 @@ BigSwitch: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p.fmtInt64(f.Int(), verb) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p.fmtUint64(f.Uint(), verb, goSyntax) + p.fmtUint64(f.Uint(), verb) case reflect.Float32, reflect.Float64: if f.Type().Size() == 4 { p.fmtFloat32(float32(f.Float()), verb) @@ -858,9 +864,9 @@ BigSwitch: p.fmtComplex128(f.Complex(), verb) } case reflect.String: - p.fmtString(f.String(), verb, goSyntax) + p.fmtString(f.String(), verb) case reflect.Map: - if goSyntax { + if p.fmt.sharpV { p.buf.WriteString(f.Type().String()) if f.IsNil() { p.buf.WriteString("(nil)") @@ -873,23 +879,23 @@ BigSwitch: keys := f.MapKeys() for i, key := range keys { if i > 0 { - if goSyntax { + if p.fmt.sharpV { p.buf.Write(commaSpaceBytes) } else { p.buf.WriteByte(' ') } } - p.printValue(key, verb, plus, goSyntax, depth+1) + p.printValue(key, verb, depth+1) p.buf.WriteByte(':') - p.printValue(f.MapIndex(key), verb, plus, goSyntax, depth+1) + p.printValue(f.MapIndex(key), verb, depth+1) } - if goSyntax { + if p.fmt.sharpV { p.buf.WriteByte('}') } else { p.buf.WriteByte(']') } case reflect.Struct: - if goSyntax { + if p.fmt.sharpV { p.buf.WriteString(value.Type().String()) } p.add('{') @@ -897,36 +903,40 @@ BigSwitch: t := v.Type() for i := 0; i < v.NumField(); i++ { if i > 0 { - if goSyntax { + if p.fmt.sharpV { p.buf.Write(commaSpaceBytes) } else { p.buf.WriteByte(' ') } } - if plus || goSyntax { + if p.fmt.plusV || p.fmt.sharpV { if f := t.Field(i); f.Name != "" { p.buf.WriteString(f.Name) p.buf.WriteByte(':') } } - p.printValue(getField(v, i), verb, plus, goSyntax, depth+1) + p.printValue(getField(v, i), verb, depth+1) } p.buf.WriteByte('}') case reflect.Interface: value := f.Elem() if !value.IsValid() { - if goSyntax { + if p.fmt.sharpV { p.buf.WriteString(f.Type().String()) p.buf.Write(nilParenBytes) } else { p.buf.Write(nilAngleBytes) } } else { - wasString = p.printValue(value, verb, plus, goSyntax, depth+1) + wasString = p.printValue(value, verb, depth+1) } case reflect.Array, reflect.Slice: - // Byte slices are special. - if typ := f.Type(); typ.Elem().Kind() == reflect.Uint8 { + // Byte slices are special: + // - Handle []byte (== []uint8) with fmtBytes. + // - Handle []T, where T is a named byte type, with fmtBytes only + // for the s, q, an x verbs. For other verbs, T might be a + // Stringer, so we use printValue to print each element. + if typ := f.Type(); typ.Elem().Kind() == reflect.Uint8 && (typ.Elem() == byteType || verb == 's' || verb == 'q' || verb == 'x') { var bytes []byte if f.Kind() == reflect.Slice { bytes = f.Bytes() @@ -941,11 +951,11 @@ BigSwitch: bytes[i] = byte(f.Index(i).Uint()) } } - p.fmtBytes(bytes, verb, goSyntax, typ, depth) + p.fmtBytes(bytes, verb, typ, depth) wasString = verb == 's' break } - if goSyntax { + if p.fmt.sharpV { p.buf.WriteString(value.Type().String()) if f.Kind() == reflect.Slice && f.IsNil() { p.buf.WriteString("(nil)") @@ -957,15 +967,15 @@ BigSwitch: } for i := 0; i < f.Len(); i++ { if i > 0 { - if goSyntax { + if p.fmt.sharpV { p.buf.Write(commaSpaceBytes) } else { p.buf.WriteByte(' ') } } - p.printValue(f.Index(i), verb, plus, goSyntax, depth+1) + p.printValue(f.Index(i), verb, depth+1) } - if goSyntax { + if p.fmt.sharpV { p.buf.WriteByte('}') } else { p.buf.WriteByte(']') @@ -978,17 +988,21 @@ BigSwitch: switch a := f.Elem(); a.Kind() { case reflect.Array, reflect.Slice: p.buf.WriteByte('&') - p.printValue(a, verb, plus, goSyntax, depth+1) + p.printValue(a, verb, depth+1) break BigSwitch case reflect.Struct: p.buf.WriteByte('&') - p.printValue(a, verb, plus, goSyntax, depth+1) + p.printValue(a, verb, depth+1) + break BigSwitch + case reflect.Map: + p.buf.WriteByte('&') + p.printValue(a, verb, depth+1) break BigSwitch } } fallthrough case reflect.Chan, reflect.Func, reflect.UnsafePointer: - p.fmtPointer(value, verb, goSyntax) + p.fmtPointer(value, verb) default: p.unknownType(f) } @@ -1154,9 +1168,19 @@ func (p *pp) doPrintf(format string, a []interface{}) { arg := a[argNum] argNum++ - goSyntax := c == 'v' && p.fmt.sharp - plus := c == 'v' && p.fmt.plus - p.printArg(arg, c, plus, goSyntax, 0) + if c == 'v' { + if p.fmt.sharp { + // Go syntax. Set the flag in the fmt and clear the sharp flag. + p.fmt.sharp = false + p.fmt.sharpV = true + } + if p.fmt.plus { + // Struct-field syntax. Set the flag in the fmt and clear the plus flag. + p.fmt.plus = false + p.fmt.plusV = true + } + } + p.printArg(arg, c, 0) } // Check for extra arguments unless the call accessed the arguments @@ -1170,7 +1194,7 @@ func (p *pp) doPrintf(format string, a []interface{}) { p.buf.WriteString(reflect.TypeOf(arg).String()) p.buf.WriteByte('=') } - p.printArg(arg, 'v', false, false, 0) + p.printArg(arg, 'v', 0) if argNum+1 < len(a) { p.buf.Write(commaSpaceBytes) } @@ -1191,7 +1215,7 @@ func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) { p.buf.WriteByte(' ') } } - prevString = p.printArg(arg, 'v', false, false, 0) + prevString = p.printArg(arg, 'v', 0) } if addnewline { p.buf.WriteByte('\n') diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go index 8a337e4..d7befea 100644 --- a/libgo/go/fmt/scan.go +++ b/libgo/go/fmt/scan.go @@ -360,6 +360,7 @@ func (r *readRune) ReadRune() (rr rune, size int, err error) { } if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case rr = rune(r.buf[0]) + size = 1 // Known to be 1. return } var n int diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go index d903f0c..541e12d 100644 --- a/libgo/go/fmt/scan_test.go +++ b/libgo/go/fmt/scan_test.go @@ -842,6 +842,38 @@ func TestLineByLineFscanf(t *testing.T) { } } +// TestScanStateCount verifies the correct byte count is returned. Issue 8512. + +// runeScanner implements the Scanner interface for TestScanStateCount. +type runeScanner struct { + rune rune + size int +} + +func (rs *runeScanner) Scan(state ScanState, verb rune) error { + r, size, err := state.ReadRune() + rs.rune = r + rs.size = size + return err +} + +func TestScanStateCount(t *testing.T) { + var a, b, c runeScanner + n, err := Sscanf("12➂", "%c%c%c", &a, &b, &c) + if err != nil { + t.Fatal(err) + } + if n != 3 { + t.Fatalf("expected 3 items consumed, got %d") + } + if a.rune != '1' || b.rune != '2' || c.rune != '➂' { + t.Errorf("bad scan rune: %q %q %q should be '1' '2' '➂'", a.rune, b.rune, c.rune) + } + if a.size != 1 || b.size != 1 || c.size != 3 { + t.Errorf("bad scan size: %q %q %q should be 1 1 3", a.size, b.size, c.size) + } +} + // RecursiveInt accepts a string matching %d.%d.%d.... // and parses it into a linked list. // It allows us to benchmark recursive descent style scanners. |