fmt.Print*: reimplement to switch on type first.
This shortens, simplifies and regularizes the code significantly.
(Improvements to reflect could make another step.)
Passes all.bash.
One semantic change occurs: The String() method changes
behavior. It used to run only for string formats such as %s and %q.
Instead, it now runs whenever the item has the method and the
result is then processed by the format as a string. Besides the
regularization, this has three effects:
1) width is honored for String() items
2) %x works for String() items
3) implementations of String that merely recur will recur forever
Regarding point 3, example from the updated documentation:
type X int
func (x X) String() string { return Sprintf("%d", x) }
should cast the value before recurring:
func (x X) String() string { return Sprintf("%d", int(x)) }
R=rsc
CC=golang-dev
https://golang.org/cl/1613045
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index 957ac04..d9bb167 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -13,6 +13,29 @@
"testing"
)
+type (
+ renamedBool bool
+ renamedInt int
+ renamedInt8 int8
+ renamedInt16 int16
+ renamedInt32 int32
+ renamedInt64 int64
+ renamedUint uint
+ renamedUint8 uint8
+ renamedUint16 uint16
+ renamedUint32 uint32
+ renamedUint64 uint64
+ renamedUintptr uintptr
+ renamedString string
+ renamedBytes []byte
+ renamedFloat float
+ renamedFloat32 float32
+ renamedFloat64 float64
+ renamedComplex complex
+ renamedComplex64 complex64
+ renamedComplex128 complex128
+)
+
func TestFmtInterface(t *testing.T) {
var i1 interface{}
i1 = "abc"
@@ -43,7 +66,7 @@
type I int
-func (i I) String() string { return Sprintf("<%d>", i) }
+func (i I) String() string { return Sprintf("<%d>", int(i)) }
type B struct {
i I
@@ -58,6 +81,10 @@
var b byte
var fmttests = []fmtTest{
+ fmtTest{"%d", 12345, "12345"},
+ fmtTest{"%v", 12345, "12345"},
+ fmtTest{"%t", true, "true"},
+
// basic string
fmtTest{"%s", "abc", "abc"},
fmtTest{"%x", "abc", "616263"},
@@ -245,7 +272,10 @@
fmtTest{"%+v", C{1, B{2, 3}}, `{i:1 B:{i:<2> j:3}}`},
// q on Stringable items
+ fmtTest{"%s", I(23), `<23>`},
fmtTest{"%q", I(23), `"<23>"`},
+ fmtTest{"%x", I(23), `3c32333e`},
+ fmtTest{"%d", I(23), `%d(string=<23>)`},
// %p on non-pointers
fmtTest{"%p", make(chan int), "PTR"},
@@ -260,6 +290,30 @@
fmtTest{"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
fmtTest{"%#v", 1000000000, "1000000000"},
+ // renamings
+ fmtTest{"%v", renamedBool(true), "true"},
+ fmtTest{"%d", renamedBool(true), "%d(fmt_test.renamedBool=true)"},
+ fmtTest{"%o", renamedInt(8), "10"},
+ fmtTest{"%d", renamedInt8(-9), "-9"},
+ fmtTest{"%v", renamedInt16(10), "10"},
+ fmtTest{"%v", renamedInt32(-11), "-11"},
+ fmtTest{"%X", renamedInt64(255), "FF"},
+ fmtTest{"%v", renamedUint(13), "13"},
+ fmtTest{"%o", renamedUint8(14), "16"},
+ fmtTest{"%X", renamedUint16(15), "F"},
+ fmtTest{"%d", renamedUint32(16), "16"},
+ fmtTest{"%X", renamedUint64(17), "11"},
+ fmtTest{"%o", renamedUintptr(18), "22"},
+ fmtTest{"%x", renamedString("thing"), "7468696e67"},
+ // TODO: It would be nice if this one worked, but it's hard.
+ // fmtTest{"%q", renamedBytes([]byte("hello")), `"hello"`},
+ fmtTest{"%v", renamedFloat(11), "11"},
+ fmtTest{"%v", renamedFloat32(22), "22"},
+ fmtTest{"%v", renamedFloat64(33), "33"},
+ fmtTest{"%v", renamedComplex(7 + .2i), "(7+0.2i)"},
+ fmtTest{"%v", renamedComplex64(3 + 4i), "(3+4i)"},
+ fmtTest{"%v", renamedComplex128(4 - 3i), "(4-3i)"},
+
// erroneous things
fmtTest{"%d", "hello", "%d(string=hello)"},
fmtTest{"no args", "hello", "no args?(extra string=hello)"},
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index c7a67d3..62fc9ff 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -234,87 +234,6 @@
f.pad(buf[i:])
}
-// fmt_d64 formats an int64 in decimal.
-func (f *fmt) fmt_d64(v int64) { f.integer(v, 10, signed, ldigits) }
-
-// fmt_d32 formats an int32 in decimal.
-func (f *fmt) fmt_d32(v int32) { f.integer(int64(v), 10, signed, ldigits) }
-
-// fmt_d formats an int in decimal.
-func (f *fmt) fmt_d(v int) { f.integer(int64(v), 10, signed, ldigits) }
-
-// fmt_ud64 formats a uint64 in decimal.
-func (f *fmt) fmt_ud64(v uint64) { f.integer(int64(v), 10, unsigned, ldigits) }
-
-// fmt_ud32 formats a uint32 in decimal.
-func (f *fmt) fmt_ud32(v uint32) { f.integer(int64(v), 10, unsigned, ldigits) }
-
-// fmt_ud formats a uint in decimal.
-func (f *fmt) fmt_ud(v uint) { f.integer(int64(v), 10, unsigned, ldigits) }
-
-// fmt_x64 formats an int64 in hexadecimal.
-func (f *fmt) fmt_x64(v int64) { f.integer(v, 16, signed, ldigits) }
-
-// fmt_x32 formats an int32 in hexadecimal.
-func (f *fmt) fmt_x32(v int32) { f.integer(int64(v), 16, signed, ldigits) }
-
-// fmt_x formats an int in hexadecimal.
-func (f *fmt) fmt_x(v int) { f.integer(int64(v), 16, signed, ldigits) }
-
-// fmt_ux64 formats a uint64 in hexadecimal.
-func (f *fmt) fmt_ux64(v uint64) { f.integer(int64(v), 16, unsigned, ldigits) }
-
-// fmt_ux32 formats a uint32 in hexadecimal.
-func (f *fmt) fmt_ux32(v uint32) { f.integer(int64(v), 16, unsigned, ldigits) }
-
-// fmt_ux formats a uint in hexadecimal.
-func (f *fmt) fmt_ux(v uint) { f.integer(int64(v), 16, unsigned, ldigits) }
-
-// fmt_X64 formats an int64 in upper case hexadecimal.
-func (f *fmt) fmt_X64(v int64) { f.integer(v, 16, signed, udigits) }
-
-// fmt_X32 formats an int32 in upper case hexadecimal.
-func (f *fmt) fmt_X32(v int32) { f.integer(int64(v), 16, signed, udigits) }
-
-// fmt_X formats an int in upper case hexadecimal.
-func (f *fmt) fmt_X(v int) { f.integer(int64(v), 16, signed, udigits) }
-
-// fmt_uX64 formats a uint64 in upper case hexadecimal.
-func (f *fmt) fmt_uX64(v uint64) { f.integer(int64(v), 16, unsigned, udigits) }
-
-// fmt_uX32 formats a uint32 in upper case hexadecimal.
-func (f *fmt) fmt_uX32(v uint32) { f.integer(int64(v), 16, unsigned, udigits) }
-
-// fmt_uX formats a uint in upper case hexadecimal.
-func (f *fmt) fmt_uX(v uint) { f.integer(int64(v), 16, unsigned, udigits) }
-
-// fmt_o64 formats an int64 in octal.
-func (f *fmt) fmt_o64(v int64) { f.integer(v, 8, signed, ldigits) }
-
-// fmt_o32 formats an int32 in octal.
-func (f *fmt) fmt_o32(v int32) { f.integer(int64(v), 8, signed, ldigits) }
-
-// fmt_o formats an int in octal.
-func (f *fmt) fmt_o(v int) { f.integer(int64(v), 8, signed, ldigits) }
-
-// fmt_uo64 formats a uint64 in octal.
-func (f *fmt) fmt_uo64(v uint64) { f.integer(int64(v), 8, unsigned, ldigits) }
-
-// fmt_uo32 formats a uint32 in octal.
-func (f *fmt) fmt_uo32(v uint32) { f.integer(int64(v), 8, unsigned, ldigits) }
-
-// fmt_uo formats a uint in octal.
-func (f *fmt) fmt_uo(v uint) { f.integer(int64(v), 8, unsigned, ldigits) }
-
-// fmt_b64 formats an int64 in binary.
-func (f *fmt) fmt_b64(v int64) { f.integer(v, 2, signed, ldigits) }
-
-// fmt_ub64 formats a uint64 in binary.
-func (f *fmt) fmt_ub64(v uint64) { f.integer(int64(v), 2, unsigned, ldigits) }
-
-// fmt_c formats a Unicode character.
-func (f *fmt) fmt_c(v int) { f.padString(string(v)) }
-
// fmt_s formats a string.
func (f *fmt) fmt_s(s string) {
if f.precPresent {
@@ -422,14 +341,13 @@
// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.Ftoa32(v, 'b', 0)) }
-// fmt_c64 formats a complex64 according to its fmt_x argument.
-// TODO pass in a method rather than a byte when the compilers mature.
-func (f *fmt) fmt_c64(v complex64, fmt_x byte) {
+// fmt_c64 formats a complex64 according to the verb.
+func (f *fmt) fmt_c64(v complex64, verb int) {
f.buf.WriteByte('(')
r := real(v)
f.preserveFlags = true
for i := 0; ; i++ {
- switch fmt_x {
+ switch verb {
case 'e':
f.fmt_e32(r)
case 'E':
@@ -451,14 +369,13 @@
f.buf.Write(irparenBytes)
}
-// fmt_c128 formats a complex128 according to its fmt_x argument.
-// TODO pass in a method rather than a byte when the compilers mature.
-func (f *fmt) fmt_c128(v complex128, fmt_x byte) {
+// fmt_c128 formats a complex128 according to the verb.
+func (f *fmt) fmt_c128(v complex128, verb int) {
f.buf.WriteByte('(')
r := real(v)
f.preserveFlags = true
for i := 0; ; i++ {
- switch fmt_x {
+ switch verb {
case 'e':
f.fmt_e64(r)
case 'E':
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 7a972d8..31bd1f6 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -75,16 +75,23 @@
can be used for fine control of formatting.
If an operand implements method String() string that method
- will be used for %v, %s, or Print etc.
+ will be used to conver the object to a string, which will then
+ be formatted as required by the verb (if any). To avoid
+ recursion in cases such as
+ type X int
+ func (x X) String() string { return Sprintf("%d", x) }
+ cast the value before recurring:
+ func (x X) String() string { return Sprintf("%d", int(x)) }
Scanning:
An analogous set of functions scans formatted text to yield
- values. Scan and Scanln read from os.Stdin; Fscan and
- Fscanln read from a specified os.Reader; Sscan and Sscanln
- read from an argument string. Sscanln, Fscanln and Sscanln
- stop scanning at a newline and require that the items be
- followed by one; the other routines treat newlines as spaces.
+ values. Scan, Scanf and Scanln read from os.Stdin; Fscan,
+ Fscanf and Fscanln read from a specified os.Reader; Sscan,
+ Sscanf and Sscanln read from an argument string. Sscanln,
+ Fscanln and Sscanln stop scanning at a newline and require that
+ the items be followed by one; the other routines treat newlines
+ as spaces.
Scanf, Fscanf, and Sscanf parse the arguments according to a
format string, analogous to that of Printf. For example, "%x"
@@ -134,8 +141,6 @@
// Some constants in the form of bytes, to avoid string overhead.
// Needlessly fastidious, I suppose.
var (
- trueBytes = []byte("true")
- falseBytes = []byte("false")
commaSpaceBytes = []byte(", ")
nilAngleBytes = []byte("<nil>")
nilParenBytes = []byte("(nil)")
@@ -144,6 +149,7 @@
missingBytes = []byte("missing")
extraBytes = []byte("?(extra ")
irparenBytes = []byte("i)")
+ bytesBytes = []byte("[]byte{")
)
// State represents the printer state passed to custom formatters.
@@ -184,14 +190,6 @@
GoString() string
}
-// getter is implemented by any value that has a Get() method,
-// which means the object contains a pointer. Used by %p.
-type getter interface {
- Get() uintptr
-}
-
-const allocSize = 32
-
type pp struct {
n int
buf bytes.Buffer
@@ -262,7 +260,7 @@
// Fprintf formats according to a format specifier and writes to w.
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error os.Error) {
p := newPrinter()
- p.doprintf(format, a)
+ p.doPrintf(format, a)
n64, error := p.buf.WriteTo(w)
p.free()
return int(n64), error
@@ -277,7 +275,7 @@
// Sprintf formats according to a format specifier and returns the resulting string.
func Sprintf(format string, a ...interface{}) string {
p := newPrinter()
- p.doprintf(format, a)
+ p.doPrintf(format, a)
s := p.buf.String()
p.free()
return s
@@ -289,7 +287,7 @@
// Spaces are added between operands when neither is a string.
func Fprint(w io.Writer, a ...interface{}) (n int, error os.Error) {
p := newPrinter()
- p.doprint(a, false, false)
+ p.doPrint(a, false, false)
n64, error := p.buf.WriteTo(w)
p.free()
return int(n64), error
@@ -306,7 +304,7 @@
// Spaces are added between operands when neither is a string.
func Sprint(a ...interface{}) string {
p := newPrinter()
- p.doprint(a, false, false)
+ p.doPrint(a, false, false)
s := p.buf.String()
p.free()
return s
@@ -320,7 +318,7 @@
// Spaces are always added between operands and a newline is appended.
func Fprintln(w io.Writer, a ...interface{}) (n int, error os.Error) {
p := newPrinter()
- p.doprint(a, true, true)
+ p.doPrint(a, true, true)
n64, error := p.buf.WriteTo(w)
p.free()
return int(n64), error
@@ -337,7 +335,7 @@
// Spaces are always added between operands and a newline is appended.
func Sprintln(a ...interface{}) string {
p := newPrinter()
- p.doprint(a, true, true)
+ p.doPrint(a, true, true)
s := p.buf.String()
p.free()
return s
@@ -357,188 +355,6 @@
return val
}
-// Getters for the fields of the argument structure.
-
-func getBool(a interface{}) (val bool, ok bool) {
- // Is it a regular bool type?
- if b, ok := a.(bool); ok {
- return b, true
- }
- // Must be a renamed bool type.
- if b, ok := reflect.NewValue(a).(*reflect.BoolValue); ok {
- return b.Get(), true
- }
- return
-}
-
-func getInt(a interface{}) (val int64, signed, ok bool) {
- // Is it a predeclared integer type?
- switch i := a.(type) {
- case int:
- return int64(i), true, true
- case int8:
- return int64(i), true, true
- case int16:
- return int64(i), true, true
- case int32:
- return int64(i), true, true
- case int64:
- return i, true, true
- case uint:
- return int64(i), false, true
- case uint8:
- return int64(i), false, true
- case uint16:
- return int64(i), false, true
- case uint32:
- return int64(i), false, true
- case uint64:
- return int64(i), false, true
- case uintptr:
- return int64(i), false, true
- }
- // Must be a renamed integer type.
- switch i := reflect.NewValue(a).(type) {
- case *reflect.IntValue:
- return int64(i.Get()), true, true
- case *reflect.Int8Value:
- return int64(i.Get()), true, true
- case *reflect.Int16Value:
- return int64(i.Get()), true, true
- case *reflect.Int32Value:
- return int64(i.Get()), true, true
- case *reflect.Int64Value:
- return i.Get(), true, true
- case *reflect.UintValue:
- return int64(i.Get()), false, true
- case *reflect.Uint8Value:
- return int64(i.Get()), false, true
- case *reflect.Uint16Value:
- return int64(i.Get()), false, true
- case *reflect.Uint32Value:
- return int64(i.Get()), false, true
- case *reflect.Uint64Value:
- return int64(i.Get()), false, true
- case *reflect.UintptrValue:
- return int64(i.Get()), false, true
- }
- return
-}
-
-func getString(a interface{}) (val string, ok bool) {
- if a == nil {
- return "<nil>", ok
- }
- // Is it a regular string or []byte type?
- switch s := a.(type) {
- case string:
- return s, true
- case []byte:
- return string(s), true
- }
- // Must be a renamed string or []byte type.
- v := reflect.NewValue(a)
- if s, ok := v.(*reflect.StringValue); ok {
- return s.Get(), true
- }
- if bytes, ok := v.Interface().([]byte); ok {
- return string(bytes), true
- }
- return
-}
-
-var floatBits = reflect.Typeof(float(0)).Size() * 8
-
-func getFloat32(a interface{}) (val float32, ok bool) {
- // Is it a regular floating-point type?
- switch f := a.(type) {
- case float32:
- return f, true
- case float:
- if floatBits == 32 {
- return float32(f), true
- }
- }
- // Must be a renamed floating-point type.
- switch f := reflect.NewValue(a).(type) {
- case *reflect.Float32Value:
- return float32(f.Get()), true
- case *reflect.FloatValue:
- if floatBits == 32 {
- return float32(f.Get()), true
- }
- }
- return
-}
-
-func getFloat64(a interface{}) (val float64, ok bool) {
- // Is it a regular floating-point type?
- switch f := a.(type) {
- case float64:
- return f, true
- case float:
- if floatBits == 64 {
- return float64(f), true
- }
- }
- // Must be a renamed floating-point type.
- switch f := reflect.NewValue(a).(type) {
- case *reflect.Float64Value:
- return float64(f.Get()), true
- case *reflect.FloatValue:
- if floatBits == 64 {
- return float64(f.Get()), true
- }
- }
- return
-}
-
-var complexBits = reflect.Typeof(complex(0i)).Size() * 8
-
-func getComplex64(a interface{}) (val complex64, ok bool) {
- // Is it a regular complex type?
- switch c := a.(type) {
- case complex64:
- return c, true
- case complex:
- if complexBits == 64 {
- return complex64(c), true
- }
- }
- // Must be a renamed complex type.
- switch c := reflect.NewValue(a).(type) {
- case *reflect.Complex64Value:
- return complex64(c.Get()), true
- case *reflect.ComplexValue:
- if complexBits == 64 {
- return complex64(c.Get()), true
- }
- }
- return
-}
-
-func getComplex128(a interface{}) (val complex128, ok bool) {
- // Is it a regular complex type?
- switch c := a.(type) {
- case complex128:
- return c, true
- case complex:
- if complexBits == 128 {
- return complex128(c), true
- }
- }
- // Must be a renamed complex type.
- switch c := reflect.NewValue(a).(type) {
- case *reflect.Complex128Value:
- return complex128(c.Get()), true
- case *reflect.ComplexValue:
- if complexBits == 128 {
- return complex128(c.Get()), true
- }
- }
- return
-}
-
// Convert ASCII to integer. n is 0 (and got is false) if no number present.
func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
if start >= end {
@@ -551,6 +367,7 @@
return
}
+// Reflection values like reflect.FuncValue implement this method. We use it for %p.
type uintptrGetter interface {
Get() uintptr
}
@@ -565,17 +382,250 @@
p.buf.WriteByte('?')
}
-func (p *pp) printField(field interface{}, plus, sharp bool, depth int) (was_string bool) {
- if field != nil && depth >= 0 {
+func (p *pp) badVerb(verb int, val interface{}) {
+ p.add('%')
+ p.add(verb)
+ p.add('(')
+ if val == nil {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.buf.WriteString(reflect.Typeof(val).String())
+ p.add('=')
+ p.printField(val, 'v', false, false, 0)
+ }
+ p.add(')')
+}
+
+func (p *pp) fmtBool(v bool, verb int, value interface{}) {
+ switch verb {
+ case 't', 'v':
+ p.fmt.fmt_boolean(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+// fmtC formats a rune for the 'c' format.
+func (p *pp) fmtC(c int64) {
+ rune := int(c) // Check for overflow.
+ if int64(rune) != c {
+ rune = utf8.RuneError
+ }
+ w := utf8.EncodeRune(rune, p.runeBuf[0:utf8.UTFMax])
+ p.fmt.pad(p.runeBuf[0:w])
+}
+
+func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.integer(v, 2, signed, ldigits)
+ case 'c':
+ p.fmtC(v)
+ case 'd', 'v':
+ p.fmt.integer(v, 10, signed, ldigits)
+ case 'o':
+ p.fmt.integer(v, 8, signed, ldigits)
+ case 'x':
+ p.fmt.integer(v, 16, signed, ldigits)
+ case 'X':
+ p.fmt.integer(v, 16, signed, udigits)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+// fmt_sharpHex64 formats a uint64 in hexadecimal and prefixes it with 0x by
+// temporarily turning on the sharp flag.
+func (p *pp) fmt0x64(v uint64) {
+ sharp := p.fmt.sharp
+ p.fmt.sharp = true // turn on 0x
+ p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ p.fmt.sharp = sharp
+}
+
+func (p *pp) fmtUint64(v uint64, verb int, sharp bool, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.integer(int64(v), 2, unsigned, ldigits)
+ case 'c':
+ p.fmtC(int64(v))
+ case 'd':
+ p.fmt.integer(int64(v), 10, unsigned, ldigits)
+ case 'v':
+ if sharp {
+ p.fmt0x64(v)
+ } else {
+ p.fmt.integer(int64(v), 10, unsigned, ldigits)
+ }
+ case 'o':
+ p.fmt.integer(int64(v), 8, unsigned, ldigits)
+ case 'x':
+ p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ case 'X':
+ p.fmt.integer(int64(v), 16, unsigned, udigits)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+var floatBits = reflect.Typeof(float(0)).Size() * 8
+
+func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.fmt_fb32(v)
+ case 'e':
+ p.fmt.fmt_e32(v)
+ case 'E':
+ p.fmt.fmt_E32(v)
+ case 'f':
+ p.fmt.fmt_f32(v)
+ case 'g', 'v':
+ p.fmt.fmt_g32(v)
+ case 'G':
+ p.fmt.fmt_G32(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.fmt_fb64(v)
+ case 'e':
+ p.fmt.fmt_e64(v)
+ case 'E':
+ p.fmt.fmt_E64(v)
+ case 'f':
+ p.fmt.fmt_f64(v)
+ case 'g', 'v':
+ p.fmt.fmt_g64(v)
+ case 'G':
+ p.fmt.fmt_G64(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+var complexBits = reflect.Typeof(complex(0i)).Size() * 8
+
+func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) {
+ switch verb {
+ case 'e', 'E', 'f', 'F', 'g', 'G':
+ p.fmt.fmt_c64(v, verb)
+ case 'v':
+ p.fmt.fmt_c64(v, 'g')
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) {
+ switch verb {
+ case 'e', 'E', 'f', 'F', 'g', 'G':
+ p.fmt.fmt_c128(v, verb)
+ case 'v':
+ p.fmt.fmt_c128(v, 'g')
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtString(v string, verb int, sharp bool, value interface{}) {
+ switch verb {
+ case 'v':
+ if sharp {
+ p.fmt.fmt_q(v)
+ } else {
+ p.fmt.fmt_s(v)
+ }
+ case 's':
+ p.fmt.fmt_s(v)
+ case 'x':
+ p.fmt.fmt_sx(v)
+ case 'X':
+ p.fmt.fmt_sX(v)
+ case 'q':
+ p.fmt.fmt_q(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtBytes(v []byte, verb int, sharp bool, depth int, value interface{}) {
+ if verb == 'v' {
+ if p.fmt.sharp {
+ p.buf.Write(bytesBytes)
+ } else {
+ p.buf.WriteByte('[')
+ }
+ for i, c := range v {
+ if i > 0 {
+ if p.fmt.sharp {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(c, 'v', p.fmt.plus, p.fmt.sharp, depth+1)
+ }
+ if sharp {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ return
+ }
+ s := string(v)
+ switch verb {
+ case 's':
+ p.fmt.fmt_s(s)
+ case 'x':
+ p.fmt.fmt_sx(s)
+ case 'X':
+ p.fmt.fmt_sX(s)
+ case 'q':
+ p.fmt.fmt_q(s)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtUintptrGetter(field interface{}, value reflect.Value, verb int, sharp bool) bool {
+ v, ok := value.(uintptrGetter)
+ if !ok {
+ return false
+ }
+ u := v.Get()
+ if sharp {
+ p.add('(')
+ p.buf.WriteString(reflect.Typeof(field).String())
+ p.add(')')
+ p.add('(')
+ if u == 0 {
+ p.buf.Write(nilBytes)
+ } else {
+ p.fmt0x64(uint64(v.Get()))
+ }
+ p.add(')')
+ } else {
+ p.fmt0x64(uint64(u))
+ }
+ return true
+}
+
+func (p *pp) printField(field interface{}, verb int, plus, sharp bool, depth int) (was_string bool) {
+ if field != nil {
switch {
default:
if stringer, ok := field.(Stringer); ok {
- p.buf.WriteString(stringer.String())
+ p.printField(stringer.String(), verb, plus, sharp, depth)
return false // this value is not a string
}
case sharp:
if stringer, ok := field.(GoStringer); ok {
- p.buf.WriteString(stringer.GoString())
+ p.printField(stringer.GoString(), verb, plus, sharp, depth)
return false // this value is not a string
}
}
@@ -584,83 +634,139 @@
// Some types can be done without reflection.
switch f := field.(type) {
case bool:
- p.fmt.fmt_boolean(f)
- return false
- case float32:
- p.fmt.fmt_g32(f)
- return false
- case float64:
- p.fmt.fmt_g64(f)
+ p.fmtBool(f, verb, field)
return false
case float:
if floatBits == 32 {
- p.fmt.fmt_g32(float32(f))
+ p.fmtFloat32(float32(f), verb, field)
} else {
- p.fmt.fmt_g64(float64(f))
+ p.fmtFloat64(float64(f), verb, field)
}
return false
- case complex64:
- p.fmt.fmt_c64(f, 'g')
+ case float32:
+ p.fmtFloat32(f, verb, field)
return false
- case complex128:
- p.fmt.fmt_c128(f, 'g')
+ case float64:
+ p.fmtFloat64(f, verb, field)
return false
case complex:
if complexBits == 64 {
- p.fmt.fmt_c64(complex64(f), 'g')
+ p.fmtComplex64(complex64(f), verb, field)
} else {
- p.fmt.fmt_c128(complex128(f), 'g')
+ p.fmtComplex128(complex128(f), verb, field)
}
return false
- case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr:
- v, signed, ok := getInt(field)
- if !ok {
- // cannot happen, but print something to be sure
- p.unknownType(f)
- } else {
- if signed {
- p.fmt.fmt_d64(v)
- } else {
- if sharp {
- p.fmt.sharp = true // turn on 0x
- p.fmt.fmt_ux64(uint64(v))
- } else {
- p.fmt.fmt_ud64(uint64(v))
- }
- }
- }
+ case complex64:
+ p.fmtComplex64(complex64(f), verb, field)
+ return false
+ case complex128:
+ p.fmtComplex128(f, verb, field)
+ return false
+ case int:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int8:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int16:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int32:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int64:
+ p.fmtInt64(f, verb, field)
+ return false
+ case uint:
+ p.fmtUint64(uint64(f), verb, sharp, field)
+ return false
+ case uint8:
+ p.fmtUint64(uint64(f), verb, sharp, field)
+ return false
+ case uint16:
+ p.fmtUint64(uint64(f), verb, sharp, field)
+ return false
+ case uint32:
+ p.fmtUint64(uint64(f), verb, sharp, field)
+ return false
+ case uint64:
+ p.fmtUint64(f, verb, sharp, field)
+ return false
+ case uintptr:
+ p.fmtUint64(uint64(f), verb, sharp, field)
return false
case string:
- if sharp {
- p.fmt.fmt_q(f)
- } else {
- p.fmt.fmt_s(f)
- }
- return true
+ p.fmtString(f, verb, sharp, field)
+ return verb == 's' || verb == 'v'
+ case []byte:
+ p.fmtBytes(f, verb, sharp, depth, field)
+ return verb == 's'
}
+ if field == nil {
+ if verb == 'v' {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.badVerb(verb, field)
+ }
+ return false
+ }
+
+ value := reflect.NewValue(field)
// Need to use reflection
+ // Special case for reflection values that know how to print with %p.
+ if verb == 'p' && p.fmtUintptrGetter(field, value, verb, sharp) {
+ return false
+ }
+
BigSwitch:
- switch f := reflect.NewValue(field).(type) {
+ switch f := value.(type) {
case *reflect.BoolValue:
- p.fmt.fmt_boolean(f.Get())
- case *reflect.Float32Value:
- p.fmt.fmt_g32(f.Get())
- case *reflect.Float64Value:
- p.fmt.fmt_g64(f.Get())
+ p.fmtBool(f.Get(), verb, field)
+ case *reflect.IntValue:
+ p.fmtInt64(int64(f.Get()), verb, field)
+ case *reflect.Int8Value:
+ p.fmtInt64(int64(f.Get()), verb, field)
+ case *reflect.Int16Value:
+ p.fmtInt64(int64(f.Get()), verb, field)
+ case *reflect.Int32Value:
+ p.fmtInt64(int64(f.Get()), verb, field)
+ case *reflect.Int64Value:
+ p.fmtInt64(f.Get(), verb, field)
+ case *reflect.UintValue:
+ p.fmtUint64(uint64(f.Get()), verb, sharp, field)
+ case *reflect.Uint8Value:
+ p.fmtUint64(uint64(f.Get()), verb, sharp, field)
+ case *reflect.Uint16Value:
+ p.fmtUint64(uint64(f.Get()), verb, sharp, field)
+ case *reflect.Uint32Value:
+ p.fmtUint64(uint64(f.Get()), verb, sharp, field)
+ case *reflect.Uint64Value:
+ p.fmtUint64(f.Get(), verb, sharp, field)
+ case *reflect.UintptrValue:
+ p.fmtUint64(uint64(f.Get()), verb, sharp, field)
case *reflect.FloatValue:
if floatBits == 32 {
- p.fmt.fmt_g32(float32(f.Get()))
+ p.fmtFloat32(float32(f.Get()), verb, field)
} else {
- p.fmt.fmt_g64(float64(f.Get()))
+ p.fmtFloat64(float64(f.Get()), verb, field)
}
+ case *reflect.Float32Value:
+ p.fmtFloat64(float64(f.Get()), verb, field)
+ case *reflect.Float64Value:
+ p.fmtFloat64(f.Get(), verb, field)
+ case *reflect.ComplexValue:
+ if complexBits == 64 {
+ p.fmtComplex64(complex64(f.Get()), verb, field)
+ } else {
+ p.fmtComplex128(complex128(f.Get()), verb, field)
+ }
+ case *reflect.Complex64Value:
+ p.fmtComplex64(f.Get(), verb, field)
+ case *reflect.Complex128Value:
+ p.fmtComplex128(f.Get(), verb, field)
case *reflect.StringValue:
- if sharp {
- p.fmt.fmt_q(f.Get())
- } else {
- p.fmt.fmt_s(f.Get())
- was_string = true
- }
+ p.fmtString(f.Get(), verb, sharp, field)
case *reflect.MapValue:
if sharp {
p.buf.WriteString(f.Type().String())
@@ -677,9 +783,9 @@
p.buf.WriteByte(' ')
}
}
- p.printField(key.Interface(), plus, sharp, depth+1)
+ p.printField(key.Interface(), verb, plus, sharp, depth+1)
p.buf.WriteByte(':')
- p.printField(f.Elem(key).Interface(), plus, sharp, depth+1)
+ p.printField(f.Elem(key).Interface(), verb, plus, sharp, depth+1)
}
if sharp {
p.buf.WriteByte('}')
@@ -708,7 +814,7 @@
p.buf.WriteByte(':')
}
}
- p.printField(getField(v, i).Interface(), plus, sharp, depth+1)
+ p.printField(getField(v, i).Interface(), verb, plus, sharp, depth+1)
}
p.buf.WriteByte('}')
case *reflect.InterfaceValue:
@@ -721,7 +827,7 @@
p.buf.Write(nilAngleBytes)
}
} else {
- return p.printField(value.Interface(), plus, sharp, depth+1)
+ return p.printField(value.Interface(), verb, plus, sharp, depth+1)
}
case reflect.ArrayOrSliceValue:
if sharp {
@@ -738,7 +844,7 @@
p.buf.WriteByte(' ')
}
}
- p.printField(f.Elem(i).Interface(), plus, sharp, depth+1)
+ p.printField(f.Elem(i).Interface(), verb, plus, sharp, depth+1)
}
if sharp {
p.buf.WriteByte('}')
@@ -753,11 +859,11 @@
switch a := f.Elem().(type) {
case reflect.ArrayOrSliceValue:
p.buf.WriteByte('&')
- p.printField(a.Interface(), plus, sharp, depth+1)
+ p.printField(a.Interface(), verb, plus, sharp, depth+1)
break BigSwitch
case *reflect.StructValue:
p.buf.WriteByte('&')
- p.printField(a.Interface(), plus, sharp, depth+1)
+ p.printField(a.Interface(), verb, plus, sharp, depth+1)
break BigSwitch
}
}
@@ -769,8 +875,7 @@
if v == 0 {
p.buf.Write(nilBytes)
} else {
- p.fmt.sharp = true
- p.fmt.fmt_ux64(uint64(v))
+ p.fmt0x64(uint64(v))
}
p.buf.WriteByte(')')
break
@@ -779,47 +884,19 @@
p.buf.Write(nilAngleBytes)
break
}
- p.fmt.sharp = true // turn 0x on
- p.fmt.fmt_ux64(uint64(v))
+ p.fmt0x64(uint64(v))
case uintptrGetter:
- v := f.Get()
- if sharp {
- p.buf.WriteByte('(')
- p.buf.WriteString(reflect.Typeof(field).String())
- p.buf.WriteByte(')')
- p.buf.WriteByte('(')
- if v == 0 {
- p.buf.Write(nilBytes)
- } else {
- p.fmt.sharp = true
- p.fmt.fmt_ux64(uint64(v))
- }
- p.buf.WriteByte(')')
- } else {
- p.fmt.sharp = true // turn 0x on
- p.fmt.fmt_ux64(uint64(f.Get()))
- }
- default:
- v, signed, ok := getInt(field)
- if ok {
- if signed {
- p.fmt.fmt_d64(v)
- } else {
- if sharp {
- p.fmt.sharp = true // turn on 0x
- p.fmt.fmt_ux64(uint64(v))
- } else {
- p.fmt.fmt_ud64(uint64(v))
- }
- }
+ if p.fmtUintptrGetter(field, value, verb, sharp) {
break
}
p.unknownType(f)
+ default:
+ p.unknownType(f)
}
return false
}
-func (p *pp) doprintf(format string, a []interface{}) {
+func (p *pp) doPrintf(format string, a []interface{}) {
end := len(format) - 1
fieldnum := 0 // we process one field per non-trivial format
for i := 0; i <= end; {
@@ -875,222 +952,28 @@
field := a[fieldnum]
fieldnum++
- // Try formatter except for %T,
- // which is special and handled internally.
- if field != nil && c != 'T' {
+ // %T is special; we always do it here.
+ if c == 'T' {
+ // the value's type
+ if field == nil {
+ p.buf.Write(nilAngleBytes)
+ break
+ }
+ p.buf.WriteString(reflect.Typeof(field).String())
+ continue
+ }
+
+ // Try Formatter (except for %T).
+ if field != nil {
if formatter, ok := field.(Formatter); ok {
formatter.Format(p, c)
continue
}
}
- switch c {
- // bool
- case 't':
- if v, ok := getBool(field); ok {
- if v {
- p.buf.Write(trueBytes)
- } else {
- p.buf.Write(falseBytes)
- }
- } else {
- goto badtype
- }
-
- // int
- case 'b':
- if v, signed, ok := getInt(field); ok {
- if signed {
- p.fmt.fmt_b64(v)
- } else {
- p.fmt.fmt_ub64(uint64(v))
- }
- } else if v, ok := getFloat32(field); ok {
- p.fmt.fmt_fb32(v)
- } else if v, ok := getFloat64(field); ok {
- p.fmt.fmt_fb64(v)
- } else {
- goto badtype
- }
- case 'c':
- if v, _, ok := getInt(field); ok {
- p.fmt.fmt_c(int(v))
- } else {
- goto badtype
- }
- case 'd':
- if v, signed, ok := getInt(field); ok {
- if signed {
- p.fmt.fmt_d64(v)
- } else {
- p.fmt.fmt_ud64(uint64(v))
- }
- } else {
- goto badtype
- }
- case 'o':
- if v, signed, ok := getInt(field); ok {
- if signed {
- p.fmt.fmt_o64(v)
- } else {
- p.fmt.fmt_uo64(uint64(v))
- }
- } else {
- goto badtype
- }
- case 'x':
- if v, signed, ok := getInt(field); ok {
- if signed {
- p.fmt.fmt_x64(v)
- } else {
- p.fmt.fmt_ux64(uint64(v))
- }
- } else if v, ok := getString(field); ok {
- p.fmt.fmt_sx(v)
- } else {
- goto badtype
- }
- case 'X':
- if v, signed, ok := getInt(field); ok {
- if signed {
- p.fmt.fmt_X64(v)
- } else {
- p.fmt.fmt_uX64(uint64(v))
- }
- } else if v, ok := getString(field); ok {
- p.fmt.fmt_sX(v)
- } else {
- goto badtype
- }
-
- // float/complex
- case 'e':
- if v, ok := getFloat32(field); ok {
- p.fmt.fmt_e32(v)
- } else if v, ok := getFloat64(field); ok {
- p.fmt.fmt_e64(v)
- } else if v, ok := getComplex64(field); ok {
- p.fmt.fmt_c64(v, 'e')
- } else if v, ok := getComplex128(field); ok {
- p.fmt.fmt_c128(v, 'e')
- } else {
- goto badtype
- }
- case 'E':
- if v, ok := getFloat32(field); ok {
- p.fmt.fmt_E32(v)
- } else if v, ok := getFloat64(field); ok {
- p.fmt.fmt_E64(v)
- } else if v, ok := getComplex64(field); ok {
- p.fmt.fmt_c64(v, 'E')
- } else if v, ok := getComplex128(field); ok {
- p.fmt.fmt_c128(v, 'E')
- } else {
- goto badtype
- }
- case 'f':
- if v, ok := getFloat32(field); ok {
- p.fmt.fmt_f32(v)
- } else if v, ok := getFloat64(field); ok {
- p.fmt.fmt_f64(v)
- } else if v, ok := getComplex64(field); ok {
- p.fmt.fmt_c64(v, 'f')
- } else if v, ok := getComplex128(field); ok {
- p.fmt.fmt_c128(v, 'f')
- } else {
- goto badtype
- }
- case 'g':
- if v, ok := getFloat32(field); ok {
- p.fmt.fmt_g32(v)
- } else if v, ok := getFloat64(field); ok {
- p.fmt.fmt_g64(v)
- } else if v, ok := getComplex64(field); ok {
- p.fmt.fmt_c64(v, 'g')
- } else if v, ok := getComplex128(field); ok {
- p.fmt.fmt_c128(v, 'g')
- } else {
- goto badtype
- }
- case 'G':
- if v, ok := getFloat32(field); ok {
- p.fmt.fmt_G32(v)
- } else if v, ok := getFloat64(field); ok {
- p.fmt.fmt_G64(v)
- } else if v, ok := getComplex64(field); ok {
- p.fmt.fmt_c64(v, 'G')
- } else if v, ok := getComplex128(field); ok {
- p.fmt.fmt_c128(v, 'G')
- } else {
- goto badtype
- }
-
- // string
- case 's':
- if field != nil {
- // if object implements String, use the result.
- if stringer, ok := field.(Stringer); ok {
- p.fmt.fmt_s(stringer.String())
- break
- }
- }
- if v, ok := getString(field); ok {
- p.fmt.fmt_s(v)
- } else {
- goto badtype
- }
- case 'q':
- if field != nil {
- // if object implements String, use the result.
- if stringer, ok := field.(Stringer); ok {
- p.fmt.fmt_q(stringer.String())
- break
- }
- }
- if v, ok := getString(field); ok {
- p.fmt.fmt_q(v)
- } else {
- goto badtype
- }
-
- // pointer, including addresses of reference types.
- case 'p':
- switch v := reflect.NewValue(field).(type) {
- case getter:
- p.fmt.fmt_s("0x")
- p.fmt.fmt_uX64(uint64(v.Get()))
- default:
- goto badtype
- }
-
- // arbitrary value; do your best
- case 'v':
- plus, sharp := p.fmt.plus, p.fmt.sharp
- p.fmt.plus = false
- p.fmt.sharp = false
- p.printField(field, plus, sharp, 0)
-
- // the value's type
- case 'T':
- if field == nil {
- p.buf.Write(nilAngleBytes)
- break
- }
- p.buf.WriteString(reflect.Typeof(field).String())
-
- default:
- badtype:
- p.buf.WriteByte('%')
- p.add(c)
- p.buf.WriteByte('(')
- if field != nil {
- p.buf.WriteString(reflect.Typeof(field).String())
- p.buf.WriteByte('=')
- }
- p.printField(field, false, false, -1)
- p.buf.WriteByte(')')
- }
+ p.printField(field, c, p.fmt.plus, p.fmt.sharp, 0)
}
+
if fieldnum < len(a) {
p.buf.Write(extraBytes)
for ; fieldnum < len(a); fieldnum++ {
@@ -1099,7 +982,7 @@
p.buf.WriteString(reflect.Typeof(field).String())
p.buf.WriteByte('=')
}
- p.printField(field, false, false, 0)
+ p.printField(field, 'v', false, false, 0)
if fieldnum+1 < len(a) {
p.buf.Write(commaSpaceBytes)
}
@@ -1108,7 +991,7 @@
}
}
-func (p *pp) doprint(a []interface{}, addspace, addnewline bool) {
+func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
prev_string := false
for fieldnum := 0; fieldnum < len(a); fieldnum++ {
// always add spaces if we're doing println
@@ -1119,7 +1002,7 @@
p.buf.WriteByte(' ')
}
}
- prev_string = p.printField(field, false, false, 0)
+ prev_string = p.printField(field, 'v', false, false, 0)
}
if addnewline {
p.buf.WriteByte('\n')
diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go
index 0ed53e8..d876adc 100644
--- a/src/pkg/fmt/scan_test.go
+++ b/src/pkg/fmt/scan_test.go
@@ -34,29 +34,6 @@
err string
}
-type (
- renamedBool bool
- renamedInt int
- renamedInt8 int8
- renamedInt16 int16
- renamedInt32 int32
- renamedInt64 int64
- renamedUint uint
- renamedUint8 uint8
- renamedUint16 uint16
- renamedUint32 uint32
- renamedUint64 uint64
- renamedUintptr uintptr
- renamedString string
- renamedBytes []byte
- renamedFloat float
- renamedFloat32 float32
- renamedFloat64 float64
- renamedComplex complex
- renamedComplex64 complex64
- renamedComplex128 complex128
-)
-
var (
boolVal bool
intVal int
@@ -122,7 +99,7 @@
if err != nil {
return err
}
- if !testing.MustCompile(string(verb) + "+").MatchString(tok) {
+ if !testing.MustCompile("^" + string(verb) + "+$").MatchString(tok) {
return os.ErrorString("syntax error for xs")
}
*x = Xs(tok)
diff --git a/src/pkg/fmt/stringer_test.go b/src/pkg/fmt/stringer_test.go
index e4e29be..815147e 100644
--- a/src/pkg/fmt/stringer_test.go
+++ b/src/pkg/fmt/stringer_test.go
@@ -26,21 +26,21 @@
type TB bool
type TS string
-func (v TI) String() string { return Sprintf("I: %d", v) }
-func (v TI8) String() string { return Sprintf("I8: %d", v) }
-func (v TI16) String() string { return Sprintf("I16: %d", v) }
-func (v TI32) String() string { return Sprintf("I32: %d", v) }
-func (v TI64) String() string { return Sprintf("I64: %d", v) }
-func (v TU) String() string { return Sprintf("U: %d", v) }
-func (v TU8) String() string { return Sprintf("U8: %d", v) }
-func (v TU16) String() string { return Sprintf("U16: %d", v) }
-func (v TU32) String() string { return Sprintf("U32: %d", v) }
-func (v TU64) String() string { return Sprintf("U64: %d", v) }
-func (v TUI) String() string { return Sprintf("UI: %d", v) }
-func (v TF) String() string { return Sprintf("F: %f", v) }
-func (v TF32) String() string { return Sprintf("F32: %f", v) }
-func (v TF64) String() string { return Sprintf("F64: %f", v) }
-func (v TB) String() string { return Sprintf("B: %t", v) }
+func (v TI) String() string { return Sprintf("I: %d", int(v)) }
+func (v TI8) String() string { return Sprintf("I8: %d", int8(v)) }
+func (v TI16) String() string { return Sprintf("I16: %d", int16(v)) }
+func (v TI32) String() string { return Sprintf("I32: %d", int32(v)) }
+func (v TI64) String() string { return Sprintf("I64: %d", int64(v)) }
+func (v TU) String() string { return Sprintf("U: %d", uint(v)) }
+func (v TU8) String() string { return Sprintf("U8: %d", uint8(v)) }
+func (v TU16) String() string { return Sprintf("U16: %d", uint16(v)) }
+func (v TU32) String() string { return Sprintf("U32: %d", uint32(v)) }
+func (v TU64) String() string { return Sprintf("U64: %d", uint64(v)) }
+func (v TUI) String() string { return Sprintf("UI: %d", uintptr(v)) }
+func (v TF) String() string { return Sprintf("F: %f", float(v)) }
+func (v TF32) String() string { return Sprintf("F32: %f", float32(v)) }
+func (v TF64) String() string { return Sprintf("F64: %f", float64(v)) }
+func (v TB) String() string { return Sprintf("B: %t", bool(v)) }
func (v TS) String() string { return Sprintf("S: %q", string(v)) }
func check(t *testing.T, got, want string) {