Commit d482c163 authored by Rob Pike's avatar Rob Pike

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
parent 43b3a247
......@@ -13,6 +13,29 @@ import (
"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 A struct {
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 @@ type C struct {
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 @@ var fmttests = []fmtTest{
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 @@ var fmttests = []fmtTest{
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)"},
......
......@@ -234,87 +234,6 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
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 @@ func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'G', doPrec(f,
// 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 @@ func (f *fmt) fmt_c64(v complex64, fmt_x byte) {
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':
......
......@@ -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 @@ import (
// 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 @@ var (
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 @@ type GoStringer interface {
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 @@ func (p *pp) Write(b []byte) (ret int, err os.Error) {
// 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 @@ func Printf(format string, a ...interface{}) (n int, errno os.Error) {
// 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 @@ func Sprintf(format string, a ...interface{}) string {
// 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 @@ func Print(a ...interface{}) (n int, errno os.Error) {
// 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 @@ func Sprint(a ...interface{}) string {
// 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 @@ func Println(a ...interface{}) (n int, errno os.Error) {
// 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,225 +355,277 @@ func getField(v *reflect.StructValue, i int) reflect.Value {
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
// 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 {
return 0, false, end
}
// Must be a renamed bool type.
if b, ok := reflect.NewValue(a).(*reflect.BoolValue); ok {
return b.Get(), true
for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
num = num*10 + int(s[newi]-'0')
isnum = 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
}
// Reflection values like reflect.FuncValue implement this method. We use it for %p.
type uintptrGetter interface {
Get() uintptr
}
func (p *pp) unknownType(v interface{}) {
if v == nil {
p.buf.Write(nilAngleBytes)
return
}
p.buf.WriteByte('?')
p.buf.WriteString(reflect.Typeof(v).String())
p.buf.WriteByte('?')
}
func getString(a interface{}) (val string, ok bool) {
if a == nil {
return "<nil>", ok
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)
}
// Is it a regular string or []byte type?
switch s := a.(type) {
case string:
return s, true
case []byte:
return string(s), true
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)
}
// Must be a renamed string or []byte type.
v := reflect.NewValue(a)
if s, ok := v.(*reflect.StringValue); ok {
return s.Get(), true
}
// 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
}
if bytes, ok := v.Interface().([]byte); ok {
return string(bytes), true
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)
}
return
}
var floatBits = reflect.Typeof(float(0)).Size() * 8
// 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 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
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)
}
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
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)
}
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
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)
}
// 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
}
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)
}
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
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(' ')
}
// 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
}
p.printField(c, 'v', p.fmt.plus, p.fmt.sharp, depth+1)
}
if sharp {
p.buf.WriteByte('}')
} else {
p.buf.WriteByte(']')
}
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 {
return 0, false, end
}
for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
num = num*10 + int(s[newi]-'0')
isnum = true
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)
}
return
}
type uintptrGetter interface {
Get() uintptr
}
func (p *pp) unknownType(v interface{}) {
if v == nil {
p.buf.Write(nilAngleBytes)
return
func (p *pp) fmtUintptrGetter(field interface{}, value reflect.Value, verb int, sharp bool) bool {
v, ok := value.(uintptrGetter)
if !ok {
return false
}
p.buf.WriteByte('?')
p.buf.WriteString(reflect.Typeof(v).String())
p.buf.WriteByte('?')
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{}, plus, sharp bool, depth int) (was_string bool) {
if field != nil && depth >= 0 {
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 @@ func (p *pp) printField(field interface{}, plus, sharp bool, depth int) (was_str
// 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)
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.fmt.fmt_s(f)
p.badVerb(verb, field)
}
return true
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.StringValue:
if sharp {
p.fmt.fmt_q(f.Get())
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.fmt.fmt_s(f.Get())
was_string = true
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:
p.fmtString(f.Get(), verb, sharp, field)
case *reflect.MapValue:
if sharp {
p.buf.WriteString(f.Type().String())
......@@ -677,9 +783,9 @@ BigSwitch:
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 @@ BigSwitch:
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 @@ BigSwitch:
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 @@ BigSwitch:
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 @@ BigSwitch:
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 @@ BigSwitch:
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 @@ BigSwitch:
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 @@ func (p *pp) doprintf(format string, a []interface{}) {
field := a[fieldnum]
fieldnum++
// Try formatter except for %T,
// which is special and handled internally.
if field != nil && c != 'T' {
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)
// %T is special; we always do it here.
if c == 'T' {
// the value's type
case 'T':
if field == nil {
p.buf.Write(nilAngleBytes)
break
}
p.buf.WriteString(reflect.Typeof(field).String())
continue
}
default:
badtype:
p.buf.WriteByte('%')
p.add(c)
p.buf.WriteByte('(')
// Try Formatter (except for %T).
if field != nil {
p.buf.WriteString(reflect.Typeof(field).String())
p.buf.WriteByte('=')
if formatter, ok := field.(Formatter); ok {
formatter.Format(p, c)
continue
}
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 @@ func (p *pp) doprintf(format string, a []interface{}) {
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) doprintf(format string, a []interface{}) {
}
}
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 @@ func (p *pp) doprint(a []interface{}, addspace, addnewline bool) {
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')
......
......@@ -34,29 +34,6 @@ type ScanfMultiTest struct {
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 @@ func (x *Xs) Scan(state ScanState, verb int) os.Error {
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)
......
......@@ -26,21 +26,21 @@ type TF64 float64
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) {
......
......@@ -10,7 +10,7 @@ import "fmt"
type T int
func (t T) String() string { return fmt.Sprintf("T%d", t) }
func (t T) String() string { return fmt.Sprintf("T%d", int(t)) }
const (
A T = 1 << (1 << iota)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment