aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/fmt
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/fmt')
-rw-r--r--libgo/go/fmt/doc.go24
-rw-r--r--libgo/go/fmt/errors.go43
-rw-r--r--libgo/go/fmt/errors_test.go73
-rw-r--r--libgo/go/fmt/example_test.go10
-rw-r--r--libgo/go/fmt/fmt_test.go30
-rw-r--r--libgo/go/fmt/format.go45
-rw-r--r--libgo/go/fmt/print.go232
-rw-r--r--libgo/go/fmt/scan.go70
-rw-r--r--libgo/go/fmt/scan_test.go38
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"},