diff options
Diffstat (limited to 'libgo/go/fmt')
-rw-r--r-- | libgo/go/fmt/doc.go | 24 | ||||
-rw-r--r-- | libgo/go/fmt/errors.go | 43 | ||||
-rw-r--r-- | libgo/go/fmt/errors_test.go | 73 | ||||
-rw-r--r-- | libgo/go/fmt/example_test.go | 10 | ||||
-rw-r--r-- | libgo/go/fmt/fmt_test.go | 30 | ||||
-rw-r--r-- | libgo/go/fmt/format.go | 45 | ||||
-rw-r--r-- | libgo/go/fmt/print.go | 232 | ||||
-rw-r--r-- | libgo/go/fmt/scan.go | 70 | ||||
-rw-r--r-- | libgo/go/fmt/scan_test.go | 38 |
9 files changed, 403 insertions, 162 deletions
diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go index 3b657f3..a711580 100644 --- a/libgo/go/fmt/doc.go +++ b/libgo/go/fmt/doc.go @@ -26,6 +26,7 @@ %c the character represented by the corresponding Unicode code point %d base 10 %o base 8 + %O base 8 with 0o prefix %q a single-quoted character literal safely escaped with Go syntax. %x base 16, with lower-case letters for a-f %X base 16, with upper-case letters for A-F @@ -40,6 +41,8 @@ %F synonym for %f %g %e for large exponents, %f otherwise. Precision is discussed below. %G %E for large exponents, %F otherwise + %x hexadecimal notation (with decimal power of two exponent), e.g. -0x1.23abcp+20 + %X upper-case hexadecimal notation, e.g. -0X1.23ABCP+20 String and slice of bytes (treated equivalently with these verbs): %s the uninterpreted bytes of the string or slice %q a double-quoted string safely escaped with Go syntax @@ -111,8 +114,8 @@ + always print a sign for numeric values; guarantee ASCII-only output for %q (%+q) - pad with spaces on the right rather than the left (left-justify the field) - # alternate format: add leading 0 for octal (%#o), 0x for hex (%#x); - 0X for hex (%#X); suppress 0x for %p (%#p); + # alternate format: add leading 0b for binary (%#b), 0 for octal (%#o), + 0x or 0X for hex (%#x or %#X); suppress 0x for %p (%#p); for %q, print a raw (backquoted) string if strconv.CanBackquote returns true; always print a decimal point for %e, %E, %f, %F, %g and %G; @@ -214,7 +217,7 @@ description of the problem, as in these examples: Wrong type or unknown verb: %!verb(type=value) - Printf("%d", hi): %!d(string=hi) + Printf("%d", "hi"): %!d(string=hi) Too many arguments: %!(EXTRA type=value) Printf("hi", "guys"): hi%!(EXTRA string=guys) Too few arguments: %!verb(MISSING) @@ -283,10 +286,10 @@ For example, %x will scan an integer as a hexadecimal number, and %v will scan the default representation format for the value. The Printf verbs %p and %T and the flags # and + are not implemented. - The verbs %e %E %f %F %g and %G are all equivalent and scan any - floating-point or complex value. For float and complex literals in - scientific notation, both the decimal (e) and binary (p) exponent - formats are supported (for example: "2.3e+7" and "4.5p-8"). + For floating-point and complex values, all valid formatting verbs + (%b %e %E %f %F %g %G %x %X and %v) are equivalent and accept + both decimal and hexadecimal notation (for example: "2.3e+7", "0x4.5p-8") + and digit-separating underscores (for example: "3.14159_26535_89793"). Input processed by verbs is implicitly space-delimited: the implementation of every verb except %c starts by discarding @@ -294,9 +297,10 @@ (and %v reading into a string) stops consuming input at the first space or newline character. - The familiar base-setting prefixes 0 (octal) and 0x - (hexadecimal) are accepted when scanning integers without - a format or with the %v verb. + The familiar base-setting prefixes 0b (binary), 0o and 0 (octal), + and 0x (hexadecimal) are accepted when scanning integers + without a format or with the %v verb, as are digit-separating + underscores. Width is interpreted in the input text but there is no syntax for scanning with a precision (no %5.2f, just %5f). diff --git a/libgo/go/fmt/errors.go b/libgo/go/fmt/errors.go new file mode 100644 index 0000000..6ae6c47 --- /dev/null +++ b/libgo/go/fmt/errors.go @@ -0,0 +1,43 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package fmt + +import "errors" + +// Errorf formats according to a format specifier and returns the string as a +// value that satisfies error. +// +// If the format specifier includes a %w verb with an error operand, +// the returned error will implement an Unwrap method returning the operand. It is +// invalid to include more than one %w verb or to supply it with an operand +// that does not implement the error innterface. The %w verb is otherwise +// a synonym for %v. +func Errorf(format string, a ...interface{}) error { + p := newPrinter() + p.wrapErrs = true + p.doPrintf(format, a) + s := string(p.buf) + var err error + if p.wrappedErr == nil { + err = errors.New(s) + } else { + err = &wrapError{s, p.wrappedErr} + } + p.free() + return err +} + +type wrapError struct { + msg string + err error +} + +func (e *wrapError) Error() string { + return e.msg +} + +func (e *wrapError) Unwrap() error { + return e.err +} diff --git a/libgo/go/fmt/errors_test.go b/libgo/go/fmt/errors_test.go new file mode 100644 index 0000000..0c774bc --- /dev/null +++ b/libgo/go/fmt/errors_test.go @@ -0,0 +1,73 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package fmt_test + +import ( + "errors" + "fmt" + "testing" +) + +func TestErrorf(t *testing.T) { + wrapped := errors.New("inner error") + for _, test := range []struct { + err error + wantText string + wantUnwrap error + }{{ + err: fmt.Errorf("%w", wrapped), + wantText: "inner error", + wantUnwrap: wrapped, + }, { + err: fmt.Errorf("added context: %w", wrapped), + wantText: "added context: inner error", + wantUnwrap: wrapped, + }, { + err: fmt.Errorf("%w with added context", wrapped), + wantText: "inner error with added context", + wantUnwrap: wrapped, + }, { + err: fmt.Errorf("%s %w %v", "prefix", wrapped, "suffix"), + wantText: "prefix inner error suffix", + wantUnwrap: wrapped, + }, { + err: fmt.Errorf("%[2]s: %[1]w", wrapped, "positional verb"), + wantText: "positional verb: inner error", + wantUnwrap: wrapped, + }, { + err: fmt.Errorf("%v", wrapped), + wantText: "inner error", + }, { + err: fmt.Errorf("added context: %v", wrapped), + wantText: "added context: inner error", + }, { + err: fmt.Errorf("%v with added context", wrapped), + wantText: "inner error with added context", + }, { + err: fmt.Errorf("%w is not an error", "not-an-error"), + wantText: "%!w(string=not-an-error) is not an error", + }, { + err: fmt.Errorf("wrapped two errors: %w %w", errString("1"), errString("2")), + wantText: "wrapped two errors: 1 %!w(fmt_test.errString=2)", + }, { + err: fmt.Errorf("wrapped three errors: %w %w %w", errString("1"), errString("2"), errString("3")), + wantText: "wrapped three errors: 1 %!w(fmt_test.errString=2) %!w(fmt_test.errString=3)", + }, { + err: fmt.Errorf("%w", nil), + wantText: "%!w(<nil>)", + wantUnwrap: nil, // still nil + }} { + if got, want := errors.Unwrap(test.err), test.wantUnwrap; got != want { + t.Errorf("Formatted error: %v\nerrors.Unwrap() = %v, want %v", test.err, got, want) + } + if got, want := test.err.Error(), test.wantText; got != want { + t.Errorf("err.Error() = %q, want %q", got, want) + } + } +} + +type errString string + +func (e errString) Error() string { return string(e) } diff --git a/libgo/go/fmt/example_test.go b/libgo/go/fmt/example_test.go index 64821e0..ae60abe 100644 --- a/libgo/go/fmt/example_test.go +++ b/libgo/go/fmt/example_test.go @@ -323,13 +323,13 @@ func Example_formats() { // Result: &{Kim 22} 0x010203 // See comment above. // Arrays and slices are formatted by applying the format to each element. - greats := [5]string{"Katano", "Kobayashi", "Kurosawa", "Miyazaki", "Ozu"} + greats := [5]string{"Kitano", "Kobayashi", "Kurosawa", "Miyazaki", "Ozu"} fmt.Printf("%v %q\n", greats, greats) - // Result: [Katano Kobayashi Kurosawa Miyazaki Ozu] ["Katano" "Kobayashi" "Kurosawa" "Miyazaki" "Ozu"] + // Result: [Kitano Kobayashi Kurosawa Miyazaki Ozu] ["Kitano" "Kobayashi" "Kurosawa" "Miyazaki" "Ozu"] kGreats := greats[:3] fmt.Printf("%v %q %#v\n", kGreats, kGreats, kGreats) - // Result: [Katano Kobayashi Kurosawa] ["Katano" "Kobayashi" "Kurosawa"] []string{"Katano", "Kobayashi", "Kurosawa"} + // Result: [Kitano Kobayashi Kurosawa] ["Kitano" "Kobayashi" "Kurosawa"] []string{"Kitano", "Kobayashi", "Kurosawa"} // Byte slices are special. Integer verbs like %d print the elements in // that format. The %s and %q forms treat the slice like a string. The %x @@ -360,8 +360,8 @@ func Example_formats() { // map[dachshund:false peanut:true] map[string]bool{"dachshund":false, "peanut":true} // {Kim 22} {Name:Kim Age:22} struct { Name string; Age int }{Name:"Kim", Age:22} // &{Kim 22} 0x0 - // [Katano Kobayashi Kurosawa Miyazaki Ozu] ["Katano" "Kobayashi" "Kurosawa" "Miyazaki" "Ozu"] - // [Katano Kobayashi Kurosawa] ["Katano" "Kobayashi" "Kurosawa"] []string{"Katano", "Kobayashi", "Kurosawa"} + // [Kitano Kobayashi Kurosawa Miyazaki Ozu] ["Kitano" "Kobayashi" "Kurosawa" "Miyazaki" "Ozu"] + // [Kitano Kobayashi Kurosawa] ["Kitano" "Kobayashi" "Kurosawa"] []string{"Kitano", "Kobayashi", "Kurosawa"} // [97 226 140 152] [97 226 140 152] a⌘ "a⌘" 61e28c98 61 e2 8c 98 // 1973-11-29 21:33:09 +0000 UTC "1973-11-29 21:33:09 +0000 UTC" } diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go index bc184c3..b9e3bc6 100644 --- a/libgo/go/fmt/fmt_test.go +++ b/libgo/go/fmt/fmt_test.go @@ -354,11 +354,17 @@ var fmtTests = []struct { {"%+d", -12345, "-12345"}, {"%b", 7, "111"}, {"%b", -6, "-110"}, + {"%#b", 7, "0b111"}, + {"%#b", -6, "-0b110"}, {"%b", ^uint32(0), "11111111111111111111111111111111"}, {"%b", ^uint64(0), "1111111111111111111111111111111111111111111111111111111111111111"}, {"%b", int64(-1 << 63), zeroFill("-1", 63, "")}, {"%o", 01234, "1234"}, + {"%o", -01234, "-1234"}, {"%#o", 01234, "01234"}, + {"%#o", -01234, "-01234"}, + {"%O", 01234, "0o1234"}, + {"%O", -01234, "-0o1234"}, {"%o", ^uint32(0), "37777777777"}, {"%o", ^uint64(0), "1777777777777777777777"}, {"%#X", 0, "0X0"}, @@ -413,6 +419,8 @@ var fmtTests = []struct { // floats {"%+.3e", 0.0, "+0.000e+00"}, {"%+.3e", 1.0, "+1.000e+00"}, + {"%+.3x", 0.0, "+0x0.000p+00"}, + {"%+.3x", 1.0, "+0x1.000p+00"}, {"%+.3f", -1.0, "-1.000"}, {"%+.3F", -1.0, "-1.000"}, {"%+.3F", float32(-1.0), "-1.000"}, @@ -428,6 +436,8 @@ var fmtTests = []struct { {"%+10.2f", -1.0, " -1.00"}, {"% .3E", -1.0, "-1.000E+00"}, {"% .3e", 1.0, " 1.000e+00"}, + {"% .3X", -1.0, "-0X1.000P+00"}, + {"% .3x", 1.0, " 0x1.000p+00"}, {"%+.3g", 0.0, "+0"}, {"%+.3g", 1.0, "+1"}, {"%+.3g", -1.0, "-1"}, @@ -445,17 +455,21 @@ var fmtTests = []struct { {"%#g", 1000000.0, "1.00000e+06"}, {"%#.0f", 1.0, "1."}, {"%#.0e", 1.0, "1.e+00"}, + {"%#.0x", 1.0, "0x1.p+00"}, {"%#.0g", 1.0, "1."}, {"%#.0g", 1100000.0, "1.e+06"}, {"%#.4f", 1.0, "1.0000"}, {"%#.4e", 1.0, "1.0000e+00"}, + {"%#.4x", 1.0, "0x1.0000p+00"}, {"%#.4g", 1.0, "1.000"}, {"%#.4g", 100000.0, "1.000e+05"}, {"%#.0f", 123.0, "123."}, {"%#.0e", 123.0, "1.e+02"}, + {"%#.0x", 123.0, "0x1.p+07"}, {"%#.0g", 123.0, "1.e+02"}, {"%#.4f", 123.0, "123.0000"}, {"%#.4e", 123.0, "1.2300e+02"}, + {"%#.4x", 123.0, "0x1.ec00p+06"}, {"%#.4g", 123.0, "123.0"}, {"%#.4g", 123000.0, "1.230e+05"}, {"%#9.4g", 1.0, " 1.000"}, @@ -474,17 +488,23 @@ var fmtTests = []struct { {"%20f", posInf, " +Inf"}, {"% 20F", posInf, " Inf"}, {"% 20e", negInf, " -Inf"}, + {"% 20x", negInf, " -Inf"}, {"%+20E", negInf, " -Inf"}, + {"%+20X", negInf, " -Inf"}, {"% +20g", negInf, " -Inf"}, {"%+-20G", posInf, "+Inf "}, {"%20e", NaN, " NaN"}, + {"%20x", NaN, " NaN"}, {"% +20E", NaN, " +NaN"}, + {"% +20X", NaN, " +NaN"}, {"% -20g", NaN, " NaN "}, {"%+-20G", NaN, "+NaN "}, // Zero padding does not apply to infinities and NaN. {"%+020e", posInf, " +Inf"}, + {"%+020x", posInf, " +Inf"}, {"%-020f", negInf, "-Inf "}, {"%-020E", NaN, "NaN "}, + {"%-020X", NaN, "NaN "}, // complex values {"%.f", 0i, "(0+0i)"}, @@ -492,23 +512,29 @@ var fmtTests = []struct { {"%+.f", 0i, "(+0+0i)"}, {"% +.f", 0i, "(+0+0i)"}, {"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"}, + {"%+.3x", 0i, "(+0x0.000p+00+0x0.000p+00i)"}, {"%+.3f", 0i, "(+0.000+0.000i)"}, {"%+.3g", 0i, "(+0+0i)"}, {"%+.3e", 1 + 2i, "(+1.000e+00+2.000e+00i)"}, + {"%+.3x", 1 + 2i, "(+0x1.000p+00+0x1.000p+01i)"}, {"%+.3f", 1 + 2i, "(+1.000+2.000i)"}, {"%+.3g", 1 + 2i, "(+1+2i)"}, {"%.3e", 0i, "(0.000e+00+0.000e+00i)"}, + {"%.3x", 0i, "(0x0.000p+00+0x0.000p+00i)"}, {"%.3f", 0i, "(0.000+0.000i)"}, {"%.3F", 0i, "(0.000+0.000i)"}, {"%.3F", complex64(0i), "(0.000+0.000i)"}, {"%.3g", 0i, "(0+0i)"}, {"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"}, + {"%.3x", 1 + 2i, "(0x1.000p+00+0x1.000p+01i)"}, {"%.3f", 1 + 2i, "(1.000+2.000i)"}, {"%.3g", 1 + 2i, "(1+2i)"}, {"%.3e", -1 - 2i, "(-1.000e+00-2.000e+00i)"}, + {"%.3x", -1 - 2i, "(-0x1.000p+00-0x1.000p+01i)"}, {"%.3f", -1 - 2i, "(-1.000-2.000i)"}, {"%.3g", -1 - 2i, "(-1-2i)"}, {"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"}, + {"% .3X", -1 - 2i, "(-0X1.000P+00-0X1.000P+01i)"}, {"%+.3g", 1 + 2i, "(+1+2i)"}, {"%+.3g", complex64(1 + 2i), "(+1+2i)"}, {"%#g", 1 + 2i, "(1.00000+2.00000i)"}, @@ -517,11 +543,13 @@ var fmtTests = []struct { {"%#g", -1e10 - 1.11e100i, "(-1.00000e+10-1.11000e+100i)"}, {"%#.0f", 1.23 + 1.0i, "(1.+1.i)"}, {"%#.0e", 1.23 + 1.0i, "(1.e+00+1.e+00i)"}, + {"%#.0x", 1.23 + 1.0i, "(0x1.p+00+0x1.p+00i)"}, {"%#.0g", 1.23 + 1.0i, "(1.+1.i)"}, {"%#.0g", 0 + 100000i, "(0.+1.e+05i)"}, {"%#.0g", 1230000 + 0i, "(1.e+06+0.i)"}, {"%#.4f", 1 + 1.23i, "(1.0000+1.2300i)"}, {"%#.4e", 123 + 1i, "(1.2300e+02+1.0000e+00i)"}, + {"%#.4x", 123 + 1i, "(0x1.ec00p+06+0x1.0000p+00i)"}, {"%#.4g", 123 + 1.23i, "(123.0+1.230i)"}, {"%#12.5g", 0 + 100000i, "( 0.0000 +1.0000e+05i)"}, {"%#12.5g", 1230000 - 0i, "( 1.2300e+06 +0.0000i)"}, @@ -541,7 +569,9 @@ var fmtTests = []struct { {"% f", complex(negInf, negInf), "(-Inf-Infi)"}, {"% f", complex(NaN, NaN), "( NaN+NaNi)"}, {"%8e", complex(posInf, posInf), "( +Inf +Infi)"}, + {"%8x", complex(posInf, posInf), "( +Inf +Infi)"}, {"% 8E", complex(posInf, posInf), "( Inf +Infi)"}, + {"% 8X", complex(posInf, posInf), "( Inf +Infi)"}, {"%+8f", complex(negInf, negInf), "( -Inf -Infi)"}, {"% +8g", complex(negInf, negInf), "( -Inf -Infi)"}, {"% -8G", complex(NaN, NaN), "( NaN +NaN i)"}, diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go index d6da8ae..74e600c 100644 --- a/libgo/go/fmt/format.go +++ b/libgo/go/fmt/format.go @@ -89,17 +89,17 @@ func (f *fmt) writePadding(n int) { // pad appends b to f.buf, padded on left (!f.minus) or right (f.minus). func (f *fmt) pad(b []byte) { if !f.widPresent || f.wid == 0 { - f.buf.Write(b) + f.buf.write(b) return } width := f.wid - utf8.RuneCount(b) if !f.minus { // left padding f.writePadding(width) - f.buf.Write(b) + f.buf.write(b) } else { // right padding - f.buf.Write(b) + f.buf.write(b) f.writePadding(width) } } @@ -107,17 +107,17 @@ func (f *fmt) pad(b []byte) { // padString appends s to f.buf, padded on left (!f.minus) or right (f.minus). func (f *fmt) padString(s string) { if !f.widPresent || f.wid == 0 { - f.buf.WriteString(s) + f.buf.writeString(s) return } width := f.wid - utf8.RuneCountInString(s) if !f.minus { // left padding f.writePadding(width) - f.buf.WriteString(s) + f.buf.writeString(s) } else { // right padding - f.buf.WriteString(s) + f.buf.writeString(s) f.writePadding(width) } } @@ -191,7 +191,7 @@ func (f *fmt) fmtUnicode(u uint64) { } // fmtInteger formats signed and unsigned integers. -func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, digits string) { +func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, verb rune, digits string) { negative := isSigned && int64(u) < 0 if negative { u = -u @@ -275,6 +275,12 @@ func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, digits string) { // Various prefixes: 0x, -, etc. if f.sharp { switch base { + case 2: + // Add a leading 0b. + i-- + buf[i] = 'b' + i-- + buf[i] = '0' case 8: if buf[i] != '0' { i-- @@ -288,6 +294,12 @@ func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, digits string) { buf[i] = '0' } } + if verb == 'O' { + i-- + buf[i] = 'o' + i-- + buf[i] = '0' + } if negative { i-- @@ -510,7 +522,7 @@ func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) { if f.sharp && verb != 'b' { digits := 0 switch verb { - case 'v', 'g', 'G': + case 'v', 'g', 'G', 'x': digits = prec // If no precision is set explicitly use a precision of 6. if digits == -1 { @@ -519,8 +531,8 @@ func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) { } // Buffer pre-allocated with enough room for - // exponent notations of the form "e+123". - var tailBuf [5]byte + // exponent notations of the form "e+123" or "p-1023". + var tailBuf [6]byte tail := tailBuf[:0] hasDecimalPoint := false @@ -529,9 +541,16 @@ func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) { switch num[i] { case '.': hasDecimalPoint = true - case 'e', 'E': + case 'p', 'P': tail = append(tail, num[i:]...) num = num[:i] + case 'e', 'E': + if verb != 'x' && verb != 'X' { + tail = append(tail, num[i:]...) + num = num[:i] + break + } + fallthrough default: digits-- } @@ -550,9 +569,9 @@ func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) { // If we're zero padding to the left we want the sign before the leading zeros. // Achieve this by writing the sign out and then padding the unsigned number. if f.zero && f.widPresent && f.wid > len(num) { - f.buf.WriteByte(num[0]) + f.buf.writeByte(num[0]) f.writePadding(f.wid - len(num)) - f.buf.Write(num[1:]) + f.buf.write(num[1:]) return } f.pad(num) diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go index 42fcd8b..5958691 100644 --- a/libgo/go/fmt/print.go +++ b/libgo/go/fmt/print.go @@ -5,7 +5,6 @@ package fmt import ( - "errors" "internal/fmtsort" "io" "os" @@ -75,19 +74,19 @@ type GoStringer interface { // Use simple []byte instead of bytes.Buffer to avoid large dependency. type buffer []byte -func (b *buffer) Write(p []byte) { +func (b *buffer) write(p []byte) { *b = append(*b, p...) } -func (b *buffer) WriteString(s string) { +func (b *buffer) writeString(s string) { *b = append(*b, s...) } -func (b *buffer) WriteByte(c byte) { +func (b *buffer) writeByte(c byte) { *b = append(*b, c) } -func (bp *buffer) WriteRune(r rune) { +func (bp *buffer) writeRune(r rune) { if r < utf8.RuneSelf { *bp = append(*bp, byte(r)) return @@ -123,6 +122,10 @@ type pp struct { panicking bool // erroring is set when printing an error string to guard against calling handleMethods. erroring bool + // wrapErrs is set when the format string may contain a %w verb. + wrapErrs bool + // wrappedErr records the target of the %w verb. + wrappedErr error } var ppFree = sync.Pool{ @@ -134,6 +137,7 @@ func newPrinter() *pp { p := ppFree.Get().(*pp) p.panicking = false p.erroring = false + p.wrapErrs = false p.fmt.init(&p.buf) return p } @@ -153,6 +157,7 @@ func (p *pp) free() { p.buf = p.buf[:0] p.arg = nil p.value = reflect.Value{} + p.wrappedErr = nil ppFree.Put(p) } @@ -179,14 +184,14 @@ func (p *pp) Flag(b int) bool { // 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 error) { - p.buf.Write(b) + p.buf.write(b) return len(b), nil } // Implement WriteString so that we can call io.WriteString // on a pp (through state), for efficiency. func (p *pp) WriteString(s string) (ret int, err error) { - p.buf.WriteString(s) + p.buf.writeString(s) return len(s), nil } @@ -217,12 +222,6 @@ func Sprintf(format string, a ...interface{}) string { return s } -// Errorf formats according to a format specifier and returns the string -// 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 // Fprint formats using the default formats for its operands and writes to w. @@ -320,32 +319,32 @@ func parsenum(s string, start, end int) (num int, isnum bool, newi int) { func (p *pp) unknownType(v reflect.Value) { if !v.IsValid() { - p.buf.WriteString(nilAngleString) + p.buf.writeString(nilAngleString) return } - p.buf.WriteByte('?') - p.buf.WriteString(v.Type().String()) - p.buf.WriteByte('?') + p.buf.writeByte('?') + p.buf.writeString(v.Type().String()) + p.buf.writeByte('?') } func (p *pp) badVerb(verb rune) { p.erroring = true - p.buf.WriteString(percentBangString) - p.buf.WriteRune(verb) - p.buf.WriteByte('(') + p.buf.writeString(percentBangString) + p.buf.writeRune(verb) + p.buf.writeByte('(') switch { case p.arg != nil: - p.buf.WriteString(reflect.TypeOf(p.arg).String()) - p.buf.WriteByte('=') + p.buf.writeString(reflect.TypeOf(p.arg).String()) + p.buf.writeByte('=') p.printArg(p.arg, 'v') case p.value.IsValid(): - p.buf.WriteString(p.value.Type().String()) - p.buf.WriteByte('=') + p.buf.writeString(p.value.Type().String()) + p.buf.writeByte('=') p.printValue(p.value, 'v', 0) default: - p.buf.WriteString(nilAngleString) + p.buf.writeString(nilAngleString) } - p.buf.WriteByte(')') + p.buf.writeByte(')') p.erroring = false } @@ -363,7 +362,7 @@ func (p *pp) fmtBool(v bool, verb rune) { func (p *pp) fmt0x64(v uint64, leading0x bool) { sharp := p.fmt.sharp p.fmt.sharp = leading0x - p.fmt.fmtInteger(v, 16, unsigned, ldigits) + p.fmt.fmtInteger(v, 16, unsigned, 'v', ldigits) p.fmt.sharp = sharp } @@ -374,18 +373,18 @@ func (p *pp) fmtInteger(v uint64, isSigned bool, verb rune) { if p.fmt.sharpV && !isSigned { p.fmt0x64(v, true) } else { - p.fmt.fmtInteger(v, 10, isSigned, ldigits) + p.fmt.fmtInteger(v, 10, isSigned, verb, ldigits) } case 'd': - p.fmt.fmtInteger(v, 10, isSigned, ldigits) + p.fmt.fmtInteger(v, 10, isSigned, verb, ldigits) case 'b': - p.fmt.fmtInteger(v, 2, isSigned, ldigits) - case 'o': - p.fmt.fmtInteger(v, 8, isSigned, ldigits) + p.fmt.fmtInteger(v, 2, isSigned, verb, ldigits) + case 'o', 'O': + p.fmt.fmtInteger(v, 8, isSigned, verb, ldigits) case 'x': - p.fmt.fmtInteger(v, 16, isSigned, ldigits) + p.fmt.fmtInteger(v, 16, isSigned, verb, ldigits) case 'X': - p.fmt.fmtInteger(v, 16, isSigned, udigits) + p.fmt.fmtInteger(v, 16, isSigned, verb, udigits) case 'c': p.fmt.fmtC(v) case 'q': @@ -407,7 +406,7 @@ func (p *pp) fmtFloat(v float64, size int, verb rune) { switch verb { case 'v': p.fmt.fmtFloat(v, size, 'g', -1) - case 'b', 'g', 'G': + case 'b', 'g', 'G', 'x', 'X': p.fmt.fmtFloat(v, size, verb, -1) case 'f', 'e', 'E': p.fmt.fmtFloat(v, size, verb, 6) @@ -425,14 +424,14 @@ func (p *pp) fmtComplex(v complex128, size int, verb rune) { // Make sure any unsupported verbs are found before the // calls to fmtFloat to not generate an incorrect error string. switch verb { - case 'v', 'b', 'g', 'G', 'f', 'F', 'e', 'E': + case 'v', 'b', 'g', 'G', 'x', 'X', 'f', 'F', 'e', 'E': oldPlus := p.fmt.plus - p.buf.WriteByte('(') + p.buf.writeByte('(') p.fmtFloat(real(v), size/2, verb) // Imaginary part always has a sign. p.fmt.plus = true p.fmtFloat(imag(v), size/2, verb) - p.buf.WriteString("i)") + p.buf.writeString("i)") p.fmt.plus = oldPlus default: p.badVerb(verb) @@ -464,28 +463,28 @@ func (p *pp) fmtBytes(v []byte, verb rune, typeString string) { switch verb { case 'v', 'd': if p.fmt.sharpV { - p.buf.WriteString(typeString) + p.buf.writeString(typeString) if v == nil { - p.buf.WriteString(nilParenString) + p.buf.writeString(nilParenString) return } - p.buf.WriteByte('{') + p.buf.writeByte('{') for i, c := range v { if i > 0 { - p.buf.WriteString(commaSpaceString) + p.buf.writeString(commaSpaceString) } p.fmt0x64(uint64(c), true) } - p.buf.WriteByte('}') + p.buf.writeByte('}') } else { - p.buf.WriteByte('[') + p.buf.writeByte('[') for i, c := range v { if i > 0 { - p.buf.WriteByte(' ') + p.buf.writeByte(' ') } - p.fmt.fmtInteger(uint64(c), 10, unsigned, ldigits) + p.fmt.fmtInteger(uint64(c), 10, unsigned, verb, ldigits) } - p.buf.WriteByte(']') + p.buf.writeByte(']') } case 's': p.fmt.fmtBs(v) @@ -513,15 +512,15 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune) { switch verb { case 'v': if p.fmt.sharpV { - p.buf.WriteByte('(') - p.buf.WriteString(value.Type().String()) - p.buf.WriteString(")(") + p.buf.writeByte('(') + p.buf.writeString(value.Type().String()) + p.buf.writeString(")(") if u == 0 { - p.buf.WriteString(nilString) + p.buf.writeString(nilString) } else { p.fmt0x64(uint64(u), true) } - p.buf.WriteByte(')') + p.buf.writeByte(')') } else { if u == 0 { p.fmt.padString(nilAngleString) @@ -544,7 +543,7 @@ func (p *pp) catchPanic(arg interface{}, verb rune, method string) { // 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(arg); v.Kind() == reflect.Ptr && v.IsNil() { - p.buf.WriteString(nilAngleString) + p.buf.writeString(nilAngleString) return } // Otherwise print a concise panic message. Most of the time the panic @@ -558,15 +557,15 @@ func (p *pp) catchPanic(arg interface{}, verb rune, method string) { // For this output we want default behavior. p.fmt.clearflags() - p.buf.WriteString(percentBangString) - p.buf.WriteRune(verb) - p.buf.WriteString(panicString) - p.buf.WriteString(method) - p.buf.WriteString(" method: ") + p.buf.writeString(percentBangString) + p.buf.writeRune(verb) + p.buf.writeString(panicString) + p.buf.writeString(method) + p.buf.writeString(" method: ") p.panicking = true p.printArg(err, 'v') p.panicking = false - p.buf.WriteByte(')') + p.buf.writeByte(')') p.fmt.fmtFlags = oldFlags } @@ -576,6 +575,21 @@ func (p *pp) handleMethods(verb rune) (handled bool) { if p.erroring { return } + if verb == 'w' { + // It is invalid to use %w other than with Errorf, more than once, + // or with a non-error arg. + err, ok := p.arg.(error) + if !ok || !p.wrapErrs || p.wrappedErr != nil { + p.wrappedErr = nil + p.wrapErrs = false + p.badVerb(verb) + return true + } + p.wrappedErr = err + // If the arg is a Formatter, pass 'v' as the verb to it. + verb = 'v' + } + // Is it a Formatter? if formatter, ok := p.arg.(Formatter); ok { handled = true @@ -720,11 +734,11 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) { switch f := value; value.Kind() { case reflect.Invalid: if depth == 0 { - p.buf.WriteString(invReflectString) + p.buf.writeString(invReflectString) } else { switch verb { case 'v': - p.buf.WriteString(nilAngleString) + p.buf.writeString(nilAngleString) default: p.badVerb(verb) } @@ -747,63 +761,63 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) { p.fmtString(f.String(), verb) case reflect.Map: if p.fmt.sharpV { - p.buf.WriteString(f.Type().String()) + p.buf.writeString(f.Type().String()) if f.IsNil() { - p.buf.WriteString(nilParenString) + p.buf.writeString(nilParenString) return } - p.buf.WriteByte('{') + p.buf.writeByte('{') } else { - p.buf.WriteString(mapString) + p.buf.writeString(mapString) } sorted := fmtsort.Sort(f) for i, key := range sorted.Key { if i > 0 { if p.fmt.sharpV { - p.buf.WriteString(commaSpaceString) + p.buf.writeString(commaSpaceString) } else { - p.buf.WriteByte(' ') + p.buf.writeByte(' ') } } p.printValue(key, verb, depth+1) - p.buf.WriteByte(':') + p.buf.writeByte(':') p.printValue(sorted.Value[i], verb, depth+1) } if p.fmt.sharpV { - p.buf.WriteByte('}') + p.buf.writeByte('}') } else { - p.buf.WriteByte(']') + p.buf.writeByte(']') } case reflect.Struct: if p.fmt.sharpV { - p.buf.WriteString(f.Type().String()) + p.buf.writeString(f.Type().String()) } - p.buf.WriteByte('{') + p.buf.writeByte('{') for i := 0; i < f.NumField(); i++ { if i > 0 { if p.fmt.sharpV { - p.buf.WriteString(commaSpaceString) + p.buf.writeString(commaSpaceString) } else { - p.buf.WriteByte(' ') + p.buf.writeByte(' ') } } if p.fmt.plusV || p.fmt.sharpV { if name := f.Type().Field(i).Name; name != "" { - p.buf.WriteString(name) - p.buf.WriteByte(':') + p.buf.writeString(name) + p.buf.writeByte(':') } } p.printValue(getField(f, i), verb, depth+1) } - p.buf.WriteByte('}') + p.buf.writeByte('}') case reflect.Interface: value := f.Elem() if !value.IsValid() { if p.fmt.sharpV { - p.buf.WriteString(f.Type().String()) - p.buf.WriteString(nilParenString) + p.buf.writeString(f.Type().String()) + p.buf.writeString(nilParenString) } else { - p.buf.WriteString(nilAngleString) + p.buf.writeString(nilAngleString) } } else { p.printValue(value, verb, depth+1) @@ -833,28 +847,28 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) { } } if p.fmt.sharpV { - p.buf.WriteString(f.Type().String()) + p.buf.writeString(f.Type().String()) if f.Kind() == reflect.Slice && f.IsNil() { - p.buf.WriteString(nilParenString) + p.buf.writeString(nilParenString) return } - p.buf.WriteByte('{') + p.buf.writeByte('{') for i := 0; i < f.Len(); i++ { if i > 0 { - p.buf.WriteString(commaSpaceString) + p.buf.writeString(commaSpaceString) } p.printValue(f.Index(i), verb, depth+1) } - p.buf.WriteByte('}') + p.buf.writeByte('}') } else { - p.buf.WriteByte('[') + p.buf.writeByte('[') for i := 0; i < f.Len(); i++ { if i > 0 { - p.buf.WriteByte(' ') + p.buf.writeByte(' ') } p.printValue(f.Index(i), verb, depth+1) } - p.buf.WriteByte(']') + p.buf.writeByte(']') } case reflect.Ptr: // pointer to array or slice or struct? ok at top level @@ -862,7 +876,7 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) { if depth == 0 && f.Pointer() != 0 { switch a := f.Elem(); a.Kind() { case reflect.Array, reflect.Slice, reflect.Struct, reflect.Map: - p.buf.WriteByte('&') + p.buf.writeByte('&') p.printValue(a, verb, depth+1) return } @@ -950,15 +964,15 @@ func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum } func (p *pp) badArgNum(verb rune) { - p.buf.WriteString(percentBangString) - p.buf.WriteRune(verb) - p.buf.WriteString(badIndexString) + p.buf.writeString(percentBangString) + p.buf.writeRune(verb) + p.buf.writeString(badIndexString) } func (p *pp) missingArg(verb rune) { - p.buf.WriteString(percentBangString) - p.buf.WriteRune(verb) - p.buf.WriteString(missingString) + p.buf.writeString(percentBangString) + p.buf.writeRune(verb) + p.buf.writeString(missingString) } func (p *pp) doPrintf(format string, a []interface{}) { @@ -974,7 +988,7 @@ formatLoop: i++ } if i > lasti { - p.buf.WriteString(format[lasti:i]) + p.buf.writeString(format[lasti:i]) } if i >= end { // done processing format string @@ -1032,7 +1046,7 @@ formatLoop: p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum) if !p.fmt.widPresent { - p.buf.WriteString(badWidthString) + p.buf.writeString(badWidthString) } // We have a negative width, so take its value and ensure @@ -1066,7 +1080,7 @@ formatLoop: p.fmt.precPresent = false } if !p.fmt.precPresent { - p.buf.WriteString(badPrecString) + p.buf.writeString(badPrecString) } afterIndex = false } else { @@ -1083,7 +1097,7 @@ formatLoop: } if i >= end { - p.buf.WriteString(noVerbString) + p.buf.writeString(noVerbString) break } @@ -1095,7 +1109,7 @@ formatLoop: switch { case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec. - p.buf.WriteByte('%') + p.buf.writeByte('%') case !p.goodArgNum: p.badArgNum(verb) case argNum >= len(a): // No argument left over to print for the current verb. @@ -1119,20 +1133,20 @@ formatLoop: // been used and arguably OK if they're not. if !p.reordered && argNum < len(a) { p.fmt.clearflags() - p.buf.WriteString(extraString) + p.buf.writeString(extraString) for i, arg := range a[argNum:] { if i > 0 { - p.buf.WriteString(commaSpaceString) + p.buf.writeString(commaSpaceString) } if arg == nil { - p.buf.WriteString(nilAngleString) + p.buf.writeString(nilAngleString) } else { - p.buf.WriteString(reflect.TypeOf(arg).String()) - p.buf.WriteByte('=') + p.buf.writeString(reflect.TypeOf(arg).String()) + p.buf.writeByte('=') p.printArg(arg, 'v') } } - p.buf.WriteByte(')') + p.buf.writeByte(')') } } @@ -1142,7 +1156,7 @@ func (p *pp) doPrint(a []interface{}) { isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String // Add a space between two non-string arguments. if argNum > 0 && !isString && !prevString { - p.buf.WriteByte(' ') + p.buf.writeByte(' ') } p.printArg(arg, 'v') prevString = isString @@ -1154,9 +1168,9 @@ func (p *pp) doPrint(a []interface{}) { func (p *pp) doPrintln(a []interface{}) { for argNum, arg := range a { if argNum > 0 { - p.buf.WriteByte(' ') + p.buf.writeByte(' ') } p.printArg(arg, 'v') } - p.buf.WriteByte('\n') + p.buf.writeByte('\n') } diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go index ae79e39..74ada20 100644 --- a/libgo/go/fmt/scan.go +++ b/libgo/go/fmt/scan.go @@ -457,7 +457,7 @@ func (s *ss) token(skipSpace bool, f func(rune) bool) []byte { s.UnreadRune() break } - s.buf.WriteRune(r) + s.buf.writeRune(r) } return s.buf } @@ -483,7 +483,7 @@ func (s *ss) consume(ok string, accept bool) bool { } if indexRune(ok, r) >= 0 { if accept { - s.buf.WriteRune(r) + s.buf.writeRune(r) } return true } @@ -562,7 +562,7 @@ const ( hexadecimalDigits = "0123456789aAbBcCdDeEfF" sign = "+-" period = "." - exponent = "eEp" + exponent = "eEpP" ) // getBase returns the numeric base represented by the verb and its digit string. @@ -609,22 +609,28 @@ func (s *ss) scanRune(bitSize int) int64 { return r } -// scanBasePrefix reports whether the integer begins with a 0 or 0x, +// scanBasePrefix reports whether the integer begins with a bas prefix // and returns the base, digit string, and whether a zero was found. // It is called only if the verb is %v. -func (s *ss) scanBasePrefix() (base int, digits string, found bool) { +func (s *ss) scanBasePrefix() (base int, digits string, zeroFound bool) { if !s.peek("0") { - return 10, decimalDigits, false + return 0, decimalDigits + "_", false } s.accept("0") - found = true // We've put a digit into the token buffer. - // Special cases for '0' && '0x' - base, digits = 8, octalDigits - if s.peek("xX") { - s.consume("xX", false) - base, digits = 16, hexadecimalDigits + // Special cases for 0, 0b, 0o, 0x. + switch { + case s.peek("bB"): + s.consume("bB", true) + return 0, binaryDigits + "_", true + case s.peek("oO"): + s.consume("oO", true) + return 0, octalDigits + "_", true + case s.peek("xX"): + s.consume("xX", true) + return 0, hexadecimalDigits + "_", true + default: + return 0, octalDigits + "_", true } - return } // scanInt returns the value of the integer represented by the next @@ -705,21 +711,27 @@ func (s *ss) floatToken() string { if s.accept("iI") && s.accept("nN") && s.accept("fF") { return string(s.buf) } + digits := decimalDigits + "_" + exp := exponent + if s.accept("0") && s.accept("xX") { + digits = hexadecimalDigits + "_" + exp = "pP" + } // digits? - for s.accept(decimalDigits) { + for s.accept(digits) { } // decimal point? if s.accept(period) { // fraction? - for s.accept(decimalDigits) { + for s.accept(digits) { } } // exponent? - if s.accept(exponent) { + if s.accept(exp) { // leading sign? s.accept(sign) // digits? - for s.accept(decimalDigits) { + for s.accept(decimalDigits + "_") { } } return string(s.buf) @@ -749,9 +761,21 @@ func (s *ss) complexTokens() (real, imag string) { return real, imagSign + imag } +func hasX(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] == 'x' || s[i] == 'X' { + return true + } + } + return false +} + // convertFloat converts the string to a float64value. func (s *ss) convertFloat(str string, n int) float64 { - if p := indexRune(str, 'p'); p >= 0 { + // strconv.ParseFloat will handle "+0x1.fp+2", + // but we have to implement our non-standard + // decimal+binary exponent mix (1.2p4) ourselves. + if p := indexRune(str, 'p'); p >= 0 && !hasX(str) { // Atof doesn't handle power-of-2 exponents, // but they're easy to evaluate. f, err := strconv.ParseFloat(str[:p], n) @@ -826,20 +850,20 @@ func (s *ss) quotedString() string { if r == quote { break } - s.buf.WriteRune(r) + s.buf.writeRune(r) } return string(s.buf) case '"': // Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes. - s.buf.WriteByte('"') + s.buf.writeByte('"') for { r := s.mustReadRune() - s.buf.WriteRune(r) + 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. - s.buf.WriteRune(s.mustReadRune()) + s.buf.writeRune(s.mustReadRune()) } else if r == '"' { break } @@ -898,7 +922,7 @@ func (s *ss) hexString() string { if !ok { break } - s.buf.WriteByte(b) + s.buf.writeByte(b) } if len(s.buf) == 0 { s.errorString("no hex data for %x string") diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go index d7019d9..b14a6f5 100644 --- a/libgo/go/fmt/scan_test.go +++ b/libgo/go/fmt/scan_test.go @@ -124,12 +124,18 @@ var scanTests = []ScanTest{ {"T\n", &boolVal, true}, // boolean test vals toggle to be sure they are written {"F\n", &boolVal, false}, // restored to zero value {"21\n", &intVal, 21}, + {"2_1\n", &intVal, 21}, {"0\n", &intVal, 0}, {"000\n", &intVal, 0}, {"0x10\n", &intVal, 0x10}, + {"0x_1_0\n", &intVal, 0x10}, {"-0x10\n", &intVal, -0x10}, {"0377\n", &intVal, 0377}, + {"0_3_7_7\n", &intVal, 0377}, + {"0o377\n", &intVal, 0377}, + {"0o_3_7_7\n", &intVal, 0377}, {"-0377\n", &intVal, -0377}, + {"-0o377\n", &intVal, -0377}, {"0\n", &uintVal, uint(0)}, {"000\n", &uintVal, uint(0)}, {"0x10\n", &uintVal, uint(0x10)}, @@ -163,13 +169,20 @@ var scanTests = []ScanTest{ {"2.3e2\n", &float64Val, 2.3e2}, {"2.3p2\n", &float64Val, 2.3 * 4}, {"2.3p+2\n", &float64Val, 2.3 * 4}, - {"2.3p+66\n", &float64Val, 2.3 * (1 << 32) * (1 << 32) * 4}, - {"2.3p-66\n", &float64Val, 2.3 / ((1 << 32) * (1 << 32) * 4)}, + {"2.3p+66\n", &float64Val, 2.3 * (1 << 66)}, + {"2.3p-66\n", &float64Val, 2.3 / (1 << 66)}, + {"0x2.3p-66\n", &float64Val, float64(0x23) / (1 << 70)}, + {"2_3.4_5\n", &float64Val, 23.45}, {"2.35\n", &stringVal, "2.35"}, {"2345678\n", &bytesVal, []byte("2345678")}, {"(3.4e1-2i)\n", &complex128Val, 3.4e1 - 2i}, {"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)}, {"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)}, + {"-.4_5e1-1E2i\n", &complex128Val, complex128(-.45e1 - 100i)}, + {"0x1.0p1+0x1.0P2i\n", &complex128Val, complex128(2 + 4i)}, + {"-0x1p1-0x1p2i\n", &complex128Val, complex128(-2 - 4i)}, + {"-0x1ep-1-0x1p2i\n", &complex128Val, complex128(-15 - 4i)}, + {"-0x1_Ep-1-0x1p0_2i\n", &complex128Val, complex128(-15 - 4i)}, {"hello\n", &stringVal, "hello"}, // Carriage-return followed by newline. (We treat \r\n as \n always.) @@ -207,8 +220,15 @@ var scanfTests = []ScanfTest{ {"%v", "TRUE\n", &boolVal, true}, {"%t", "false\n", &boolVal, false}, {"%v", "-71\n", &intVal, -71}, + {"%v", "-7_1\n", &intVal, -71}, + {"%v", "0b111\n", &intVal, 7}, + {"%v", "0b_1_1_1\n", &intVal, 7}, {"%v", "0377\n", &intVal, 0377}, + {"%v", "0_3_7_7\n", &intVal, 0377}, + {"%v", "0o377\n", &intVal, 0377}, + {"%v", "0o_3_7_7\n", &intVal, 0377}, {"%v", "0x44\n", &intVal, 0x44}, + {"%v", "0x_4_4\n", &intVal, 0x44}, {"%d", "72\n", &intVal, 72}, {"%c", "a\n", &runeVal, 'a'}, {"%c", "\u5072\n", &runeVal, '\u5072'}, @@ -222,17 +242,31 @@ var scanfTests = []ScanfTest{ {"%x", "a75\n", &intVal, 0xa75}, {"%v", "71\n", &uintVal, uint(71)}, {"%d", "72\n", &uintVal, uint(72)}, + {"%d", "7_2\n", &uintVal, uint(7)}, // only %v takes underscores {"%d", "73\n", &uint8Val, uint8(73)}, {"%d", "74\n", &uint16Val, uint16(74)}, {"%d", "75\n", &uint32Val, uint32(75)}, {"%d", "76\n", &uint64Val, uint64(76)}, {"%b", "1001001\n", &uintVal, uint(73)}, + {"%b", "100_1001\n", &uintVal, uint(4)}, {"%o", "075\n", &uintVal, uint(075)}, + {"%o", "07_5\n", &uintVal, uint(07)}, // only %v takes underscores {"%x", "a75\n", &uintVal, uint(0xa75)}, {"%x", "A75\n", &uintVal, uint(0xa75)}, + {"%x", "A7_5\n", &uintVal, uint(0xa7)}, // only %v takes underscores {"%U", "U+1234\n", &intVal, int(0x1234)}, {"%U", "U+4567\n", &uintVal, uint(0x4567)}, + {"%e", "2.3\n", &float64Val, 2.3}, + {"%E", "2.3e1\n", &float32Val, float32(2.3e1)}, + {"%f", "2.3e2\n", &float64Val, 2.3e2}, + {"%g", "2.3p2\n", &float64Val, 2.3 * 4}, + {"%G", "2.3p+2\n", &float64Val, 2.3 * 4}, + {"%v", "2.3p+66\n", &float64Val, 2.3 * (1 << 66)}, + {"%f", "2.3p-66\n", &float64Val, 2.3 / (1 << 66)}, + {"%G", "0x2.3p-66\n", &float64Val, float64(0x23) / (1 << 70)}, + {"%E", "2_3.4_5\n", &float64Val, 23.45}, + // Strings {"%s", "using-%s\n", &stringVal, "using-%s"}, {"%x", "7573696e672d2578\n", &stringVal, "using-%x"}, |