Commit 7c8e057a authored by Rob Pike's avatar Rob Pike

fmt: make the %#v verb a special flag

The %#v verb is special: it says all values below need to print as %#v.
However, for some situations the # flag has other meanings and this
causes some issues, particularly in how Formatters work. Since %#v
dominates all formatting, translate it into actual state of the formatter
and decouple it from the # flag itself within the calculations (although
it must be restored when methods are doing the work.)
The result is cleaner code and correct handling of # for Formatters.
TODO: Apply the same thinking to the + flag in a followup CL.

Also, the wasString return value in handleMethods is always false,
so eliminate it.

Update #8835

LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/146650043
parent 28ddfb09
...@@ -1144,10 +1144,10 @@ var panictests = []struct { ...@@ -1144,10 +1144,10 @@ var panictests = []struct {
} }
func TestPanics(t *testing.T) { func TestPanics(t *testing.T) {
for _, tt := range panictests { for i, tt := range panictests {
s := Sprintf(tt.fmt, tt.in) s := Sprintf(tt.fmt, tt.in)
if s != tt.out { if s != tt.out {
t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out) t.Errorf("%d: %q: got %q expected %q", i, tt.fmt, s, tt.out)
} }
} }
} }
...@@ -1207,3 +1207,94 @@ func TestNilDoesNotBecomeTyped(t *testing.T) { ...@@ -1207,3 +1207,94 @@ func TestNilDoesNotBecomeTyped(t *testing.T) {
t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got) t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got)
} }
} }
// Formatters did not get delivered flags correctly in all cases. Issue 8835.
type fp struct{}
func (fp) Format(f State, c rune) {
s := "%"
for i := 0; i < 128; i++ {
if f.Flag(i) {
s += string(i)
}
}
if w, ok := f.Width(); ok {
s += Sprintf("%d", w)
}
if p, ok := f.Precision(); ok {
s += Sprintf(".%d", p)
}
s += string(c)
io.WriteString(f, "["+s+"]")
}
var formatterFlagTests = []struct {
in string
val interface{}
out string
}{
// scalar values with the (unused by fmt) 'a' verb.
{"%a", fp{}, "[%a]"},
{"%-a", fp{}, "[%-a]"},
{"%+a", fp{}, "[%+a]"},
{"%#a", fp{}, "[%#a]"},
{"% a", fp{}, "[% a]"},
{"%0a", fp{}, "[%0a]"},
{"%1.2a", fp{}, "[%1.2a]"},
{"%-1.2a", fp{}, "[%-1.2a]"},
{"%+1.2a", fp{}, "[%+1.2a]"},
{"%-+1.2a", fp{}, "[%+-1.2a]"},
{"%-+1.2abc", fp{}, "[%+-1.2a]bc"},
{"%-1.2abc", fp{}, "[%-1.2a]bc"},
// composite values with the 'a' verb
{"%a", [1]fp{}, "[[%a]]"},
{"%-a", [1]fp{}, "[[%-a]]"},
{"%+a", [1]fp{}, "[[%+a]]"},
{"%#a", [1]fp{}, "[[%#a]]"},
{"% a", [1]fp{}, "[[% a]]"},
{"%0a", [1]fp{}, "[[%0a]]"},
{"%1.2a", [1]fp{}, "[[%1.2a]]"},
{"%-1.2a", [1]fp{}, "[[%-1.2a]]"},
{"%+1.2a", [1]fp{}, "[[%+1.2a]]"},
{"%-+1.2a", [1]fp{}, "[[%+-1.2a]]"},
{"%-+1.2abc", [1]fp{}, "[[%+-1.2a]]bc"},
{"%-1.2abc", [1]fp{}, "[[%-1.2a]]bc"},
// simple values with the 'v' verb
{"%v", fp{}, "[%v]"},
{"%-v", fp{}, "[%-v]"},
{"%+v", fp{}, "[%+v]"},
{"%#v", fp{}, "[%#v]"},
{"% v", fp{}, "[% v]"},
{"%0v", fp{}, "[%0v]"},
{"%1.2v", fp{}, "[%1.2v]"},
{"%-1.2v", fp{}, "[%-1.2v]"},
{"%+1.2v", fp{}, "[%+1.2v]"},
{"%-+1.2v", fp{}, "[%+-1.2v]"},
{"%-+1.2vbc", fp{}, "[%+-1.2v]bc"},
{"%-1.2vbc", fp{}, "[%-1.2v]bc"},
// composite values with the 'v' verb. Some are still broken.
{"%v", [1]fp{}, "[[%v]]"},
{"%-v", [1]fp{}, "[[%-v]]"},
//{"%+v", [1]fp{}, "[[%+v]]"},
{"%#v", [1]fp{}, "[1]fmt_test.fp{[%#v]}"},
{"% v", [1]fp{}, "[[% v]]"},
{"%0v", [1]fp{}, "[[%0v]]"},
{"%1.2v", [1]fp{}, "[[%1.2v]]"},
{"%-1.2v", [1]fp{}, "[[%-1.2v]]"},
//{"%+1.2v", [1]fp{}, "[[%+1.2v]]"},
//{"%-+1.2v", [1]fp{}, "[[%+-1.2v]]"},
//{"%-+1.2vbc", [1]fp{}, "[[%+-1.2v]]bc"},
{"%-1.2vbc", [1]fp{}, "[[%-1.2v]]bc"},
}
func TestFormatterFlags(t *testing.T) {
for _, tt := range formatterFlagTests {
s := Sprintf(tt.in, tt.val)
if s != tt.out {
t.Errorf("Sprintf(%q, %T) = %q, want %q", tt.in, tt.val, s, tt.out)
}
}
}
...@@ -49,9 +49,14 @@ type fmt struct { ...@@ -49,9 +49,14 @@ type fmt struct {
plus bool plus bool
sharp bool sharp bool
space bool space bool
unicode bool // For the format %#v, we set this flag and
uniQuote bool // Use 'x'= prefix for %U if printable. // clear the plus flag, since it is in effect
zero bool // a different, flagless format set at the top level.
// TODO: plusV could use this too.
sharpV bool
unicode bool
uniQuote bool // Use 'x'= prefix for %U if printable.
zero bool
} }
func (f *fmt) clearflags() { func (f *fmt) clearflags() {
...@@ -63,6 +68,7 @@ func (f *fmt) clearflags() { ...@@ -63,6 +68,7 @@ func (f *fmt) clearflags() {
f.plus = false f.plus = false
f.sharp = false f.sharp = false
f.space = false f.space = false
f.sharpV = false
f.unicode = false f.unicode = false
f.uniQuote = false f.uniQuote = false
f.zero = false f.zero = false
......
...@@ -317,11 +317,11 @@ func (p *pp) badVerb(verb rune) { ...@@ -317,11 +317,11 @@ func (p *pp) badVerb(verb rune) {
case p.arg != nil: case p.arg != nil:
p.buf.WriteString(reflect.TypeOf(p.arg).String()) p.buf.WriteString(reflect.TypeOf(p.arg).String())
p.add('=') p.add('=')
p.printArg(p.arg, 'v', false, false, 0) p.printArg(p.arg, 'v', false, 0)
case p.value.IsValid(): case p.value.IsValid():
p.buf.WriteString(p.value.Type().String()) p.buf.WriteString(p.value.Type().String())
p.add('=') p.add('=')
p.printValue(p.value, 'v', false, false, 0) p.printValue(p.value, 'v', false, 0)
default: default:
p.buf.Write(nilAngleBytes) p.buf.Write(nilAngleBytes)
} }
...@@ -406,7 +406,7 @@ func (p *pp) fmtUnicode(v int64) { ...@@ -406,7 +406,7 @@ func (p *pp) fmtUnicode(v int64) {
p.fmt.sharp = sharp p.fmt.sharp = sharp
} }
func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) { func (p *pp) fmtUint64(v uint64, verb rune) {
switch verb { switch verb {
case 'b': case 'b':
p.fmt.integer(int64(v), 2, unsigned, ldigits) p.fmt.integer(int64(v), 2, unsigned, ldigits)
...@@ -415,7 +415,7 @@ func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) { ...@@ -415,7 +415,7 @@ func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) {
case 'd': case 'd':
p.fmt.integer(int64(v), 10, unsigned, ldigits) p.fmt.integer(int64(v), 10, unsigned, ldigits)
case 'v': case 'v':
if goSyntax { if p.fmt.sharpV {
p.fmt0x64(v, true) p.fmt0x64(v, true)
} else { } else {
p.fmt.integer(int64(v), 10, unsigned, ldigits) p.fmt.integer(int64(v), 10, unsigned, ldigits)
...@@ -499,10 +499,10 @@ func (p *pp) fmtComplex128(v complex128, verb rune) { ...@@ -499,10 +499,10 @@ func (p *pp) fmtComplex128(v complex128, verb rune) {
} }
} }
func (p *pp) fmtString(v string, verb rune, goSyntax bool) { func (p *pp) fmtString(v string, verb rune) {
switch verb { switch verb {
case 'v': case 'v':
if goSyntax { if p.fmt.sharpV {
p.fmt.fmt_q(v) p.fmt.fmt_q(v)
} else { } else {
p.fmt.fmt_s(v) p.fmt.fmt_s(v)
...@@ -520,9 +520,9 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) { ...@@ -520,9 +520,9 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
} }
} }
func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, depth int) { func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) {
if verb == 'v' || verb == 'd' { if verb == 'v' || verb == 'd' {
if goSyntax { if p.fmt.sharpV {
if v == nil { if v == nil {
if typ == nil { if typ == nil {
p.buf.WriteString("[]byte(nil)") p.buf.WriteString("[]byte(nil)")
...@@ -543,15 +543,15 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, dept ...@@ -543,15 +543,15 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, dept
} }
for i, c := range v { for i, c := range v {
if i > 0 { if i > 0 {
if goSyntax { if p.fmt.sharpV {
p.buf.Write(commaSpaceBytes) p.buf.Write(commaSpaceBytes)
} else { } else {
p.buf.WriteByte(' ') p.buf.WriteByte(' ')
} }
} }
p.printArg(c, 'v', p.fmt.plus, goSyntax, depth+1) p.printArg(c, 'v', p.fmt.plus, depth+1)
} }
if goSyntax { if p.fmt.sharpV {
p.buf.WriteByte('}') p.buf.WriteByte('}')
} else { } else {
p.buf.WriteByte(']') p.buf.WriteByte(']')
...@@ -572,7 +572,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, dept ...@@ -572,7 +572,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, dept
} }
} }
func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) { func (p *pp) fmtPointer(value reflect.Value, verb rune) {
use0x64 := true use0x64 := true
switch verb { switch verb {
case 'p', 'v': case 'p', 'v':
...@@ -594,7 +594,7 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) { ...@@ -594,7 +594,7 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) {
return return
} }
if goSyntax { if p.fmt.sharpV {
p.add('(') p.add('(')
p.buf.WriteString(value.Type().String()) p.buf.WriteString(value.Type().String())
p.add(')') p.add(')')
...@@ -611,7 +611,7 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) { ...@@ -611,7 +611,7 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) {
if use0x64 { if use0x64 {
p.fmt0x64(uint64(u), !p.fmt.sharp) p.fmt0x64(uint64(u), !p.fmt.sharp)
} else { } else {
p.fmtUint64(uint64(u), verb, false) p.fmtUint64(uint64(u), verb)
} }
} }
} }
...@@ -636,24 +636,44 @@ func (p *pp) catchPanic(arg interface{}, verb rune) { ...@@ -636,24 +636,44 @@ func (p *pp) catchPanic(arg interface{}, verb rune) {
// Nested panics; the recursion in printArg cannot succeed. // Nested panics; the recursion in printArg cannot succeed.
panic(err) panic(err)
} }
p.fmt.clearflags() // We are done, and for this output we want default behavior.
p.buf.Write(percentBangBytes) p.buf.Write(percentBangBytes)
p.add(verb) p.add(verb)
p.buf.Write(panicBytes) p.buf.Write(panicBytes)
p.panicking = true p.panicking = true
p.printArg(err, 'v', false, false, 0) p.printArg(err, 'v', false, 0)
p.panicking = false p.panicking = false
p.buf.WriteByte(')') p.buf.WriteByte(')')
} }
} }
func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString, handled bool) { // clearSpecialFlags pushes %#v back into the regular flags and returns their old state.
func (p *pp) clearSpecialFlags() bool {
ret := p.fmt.sharpV
if ret {
p.fmt.sharp = true
p.fmt.sharpV = false
}
return ret
}
// restoreSpecialFlags, whose argument should be a call to clearSpecialFlags,
// restores the setting of the sharpV flag.
func (p *pp) restoreSpecialFlags(sharpV bool) {
if sharpV {
p.fmt.sharp = false
p.fmt.sharpV = true
}
}
func (p *pp) handleMethods(verb rune, plus bool, depth int) (handled bool) {
if p.erroring { if p.erroring {
return return
} }
// Is it a Formatter? // Is it a Formatter?
if formatter, ok := p.arg.(Formatter); ok { if formatter, ok := p.arg.(Formatter); ok {
handled = true handled = true
wasString = false defer p.restoreSpecialFlags(p.clearSpecialFlags())
defer p.catchPanic(p.arg, verb) defer p.catchPanic(p.arg, verb)
formatter.Format(p, verb) formatter.Format(p, verb)
return return
...@@ -664,14 +684,13 @@ func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString ...@@ -664,14 +684,13 @@ func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString
} }
// If we're doing Go syntax and the argument knows how to supply it, take care of it now. // If we're doing Go syntax and the argument knows how to supply it, take care of it now.
if goSyntax { if p.fmt.sharpV {
p.fmt.sharp = false
if stringer, ok := p.arg.(GoStringer); ok { if stringer, ok := p.arg.(GoStringer); ok {
wasString = false
handled = true handled = true
defer p.restoreSpecialFlags(p.clearSpecialFlags())
defer p.catchPanic(p.arg, verb) defer p.catchPanic(p.arg, verb)
// Print the result of GoString unadorned. // Print the result of GoString unadorned.
p.fmtString(stringer.GoString(), 's', false) p.fmtString(stringer.GoString(), 's')
return return
} }
} else { } else {
...@@ -682,30 +701,27 @@ func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString ...@@ -682,30 +701,27 @@ func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString
case 'v', 's', 'x', 'X', 'q': case 'v', 's', 'x', 'X', 'q':
// Is it an error or Stringer? // Is it an error or Stringer?
// The duplication in the bodies is necessary: // The duplication in the bodies is necessary:
// setting wasString and handled, and deferring catchPanic, // setting handled and deferring catchPanic
// must happen before calling the method. // must happen before calling the method.
switch v := p.arg.(type) { switch v := p.arg.(type) {
case error: case error:
wasString = false
handled = true handled = true
defer p.catchPanic(p.arg, verb) defer p.catchPanic(p.arg, verb)
p.printArg(v.Error(), verb, plus, false, depth) p.printArg(v.Error(), verb, plus, depth)
return return
case Stringer: case Stringer:
wasString = false
handled = true handled = true
defer p.catchPanic(p.arg, verb) defer p.catchPanic(p.arg, verb)
p.printArg(v.String(), verb, plus, false, depth) p.printArg(v.String(), verb, plus, depth)
return return
} }
} }
} }
handled = false return false
return
} }
func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int) (wasString bool) { func (p *pp) printArg(arg interface{}, verb rune, plus bool, depth int) (wasString bool) {
p.arg = arg p.arg = arg
p.value = reflect.Value{} p.value = reflect.Value{}
...@@ -722,10 +738,10 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int ...@@ -722,10 +738,10 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int
// %T (the value's type) and %p (its address) are special; we always do them first. // %T (the value's type) and %p (its address) are special; we always do them first.
switch verb { switch verb {
case 'T': case 'T':
p.printArg(reflect.TypeOf(arg).String(), 's', false, false, 0) p.printArg(reflect.TypeOf(arg).String(), 's', false, 0)
return false return false
case 'p': case 'p':
p.fmtPointer(reflect.ValueOf(arg), verb, goSyntax) p.fmtPointer(reflect.ValueOf(arg), verb)
return false return false
} }
...@@ -734,13 +750,9 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int ...@@ -734,13 +750,9 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int
// We could call handleMethods here and avoid this work, but // We could call handleMethods here and avoid this work, but
// handleMethods is expensive enough to be worth delaying. // handleMethods is expensive enough to be worth delaying.
oldPlus := p.fmt.plus oldPlus := p.fmt.plus
oldSharp := p.fmt.sharp
if plus { if plus {
p.fmt.plus = false p.fmt.plus = false
} }
if goSyntax {
p.fmt.sharp = false
}
// Some types can be done without reflection. // Some types can be done without reflection.
switch f := arg.(type) { switch f := arg.(type) {
...@@ -765,40 +777,39 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int ...@@ -765,40 +777,39 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int
case int64: case int64:
p.fmtInt64(f, verb) p.fmtInt64(f, verb)
case uint: case uint:
p.fmtUint64(uint64(f), verb, goSyntax) p.fmtUint64(uint64(f), verb)
case uint8: case uint8:
p.fmtUint64(uint64(f), verb, goSyntax) p.fmtUint64(uint64(f), verb)
case uint16: case uint16:
p.fmtUint64(uint64(f), verb, goSyntax) p.fmtUint64(uint64(f), verb)
case uint32: case uint32:
p.fmtUint64(uint64(f), verb, goSyntax) p.fmtUint64(uint64(f), verb)
case uint64: case uint64:
p.fmtUint64(f, verb, goSyntax) p.fmtUint64(f, verb)
case uintptr: case uintptr:
p.fmtUint64(uint64(f), verb, goSyntax) p.fmtUint64(uint64(f), verb)
case string: case string:
p.fmtString(f, verb, goSyntax) p.fmtString(f, verb)
wasString = verb == 's' || verb == 'v' wasString = verb == 's' || verb == 'v'
case []byte: case []byte:
p.fmtBytes(f, verb, goSyntax, nil, depth) p.fmtBytes(f, verb, nil, depth)
wasString = verb == 's' wasString = verb == 's'
default: default:
// Restore flags in case handleMethods finds a Formatter. // Restore flags in case handleMethods finds a Formatter.
p.fmt.plus = oldPlus p.fmt.plus = oldPlus
p.fmt.sharp = oldSharp
// If the type is not simple, it might have methods. // If the type is not simple, it might have methods.
if isString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled { if handled := p.handleMethods(verb, plus, depth); handled {
return isString return false
} }
// Need to use reflection // Need to use reflection
return p.printReflectValue(reflect.ValueOf(arg), verb, plus, goSyntax, depth) return p.printReflectValue(reflect.ValueOf(arg), verb, plus, depth)
} }
p.arg = nil p.arg = nil
return return
} }
// printValue is like printArg but starts with a reflect value, not an interface{} value. // printValue is like printArg but starts with a reflect value, not an interface{} value.
func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) { func (p *pp) printValue(value reflect.Value, verb rune, plus bool, depth int) (wasString bool) {
if !value.IsValid() { if !value.IsValid() {
if verb == 'T' || verb == 'v' { if verb == 'T' || verb == 'v' {
p.buf.Write(nilAngleBytes) p.buf.Write(nilAngleBytes)
...@@ -812,10 +823,10 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, dep ...@@ -812,10 +823,10 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, dep
// %T (the value's type) and %p (its address) are special; we always do them first. // %T (the value's type) and %p (its address) are special; we always do them first.
switch verb { switch verb {
case 'T': case 'T':
p.printArg(value.Type().String(), 's', false, false, 0) p.printArg(value.Type().String(), 's', false, 0)
return false return false
case 'p': case 'p':
p.fmtPointer(value, verb, goSyntax) p.fmtPointer(value, verb)
return false return false
} }
...@@ -825,18 +836,18 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, dep ...@@ -825,18 +836,18 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, dep
if value.CanInterface() { if value.CanInterface() {
p.arg = value.Interface() p.arg = value.Interface()
} }
if isString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled { if handled := p.handleMethods(verb, plus, depth); handled {
return isString return false
} }
return p.printReflectValue(value, verb, plus, goSyntax, depth) return p.printReflectValue(value, verb, plus, depth)
} }
var byteType = reflect.TypeOf(byte(0)) var byteType = reflect.TypeOf(byte(0))
// printReflectValue is the fallback for both printArg and printValue. // printReflectValue is the fallback for both printArg and printValue.
// It uses reflect to print the value. // It uses reflect to print the value.
func (p *pp) printReflectValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) { func (p *pp) printReflectValue(value reflect.Value, verb rune, plus bool, depth int) (wasString bool) {
oldValue := p.value oldValue := p.value
p.value = value p.value = value
BigSwitch: BigSwitch:
...@@ -846,7 +857,7 @@ BigSwitch: ...@@ -846,7 +857,7 @@ BigSwitch:
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p.fmtInt64(f.Int(), verb) p.fmtInt64(f.Int(), verb)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p.fmtUint64(f.Uint(), verb, goSyntax) p.fmtUint64(f.Uint(), verb)
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
if f.Type().Size() == 4 { if f.Type().Size() == 4 {
p.fmtFloat32(float32(f.Float()), verb) p.fmtFloat32(float32(f.Float()), verb)
...@@ -860,9 +871,9 @@ BigSwitch: ...@@ -860,9 +871,9 @@ BigSwitch:
p.fmtComplex128(f.Complex(), verb) p.fmtComplex128(f.Complex(), verb)
} }
case reflect.String: case reflect.String:
p.fmtString(f.String(), verb, goSyntax) p.fmtString(f.String(), verb)
case reflect.Map: case reflect.Map:
if goSyntax { if p.fmt.sharpV {
p.buf.WriteString(f.Type().String()) p.buf.WriteString(f.Type().String())
if f.IsNil() { if f.IsNil() {
p.buf.WriteString("(nil)") p.buf.WriteString("(nil)")
...@@ -875,23 +886,23 @@ BigSwitch: ...@@ -875,23 +886,23 @@ BigSwitch:
keys := f.MapKeys() keys := f.MapKeys()
for i, key := range keys { for i, key := range keys {
if i > 0 { if i > 0 {
if goSyntax { if p.fmt.sharpV {
p.buf.Write(commaSpaceBytes) p.buf.Write(commaSpaceBytes)
} else { } else {
p.buf.WriteByte(' ') p.buf.WriteByte(' ')
} }
} }
p.printValue(key, verb, plus, goSyntax, depth+1) p.printValue(key, verb, plus, depth+1)
p.buf.WriteByte(':') p.buf.WriteByte(':')
p.printValue(f.MapIndex(key), verb, plus, goSyntax, depth+1) p.printValue(f.MapIndex(key), verb, plus, depth+1)
} }
if goSyntax { if p.fmt.sharpV {
p.buf.WriteByte('}') p.buf.WriteByte('}')
} else { } else {
p.buf.WriteByte(']') p.buf.WriteByte(']')
} }
case reflect.Struct: case reflect.Struct:
if goSyntax { if p.fmt.sharpV {
p.buf.WriteString(value.Type().String()) p.buf.WriteString(value.Type().String())
} }
p.add('{') p.add('{')
...@@ -899,32 +910,32 @@ BigSwitch: ...@@ -899,32 +910,32 @@ BigSwitch:
t := v.Type() t := v.Type()
for i := 0; i < v.NumField(); i++ { for i := 0; i < v.NumField(); i++ {
if i > 0 { if i > 0 {
if goSyntax { if p.fmt.sharpV {
p.buf.Write(commaSpaceBytes) p.buf.Write(commaSpaceBytes)
} else { } else {
p.buf.WriteByte(' ') p.buf.WriteByte(' ')
} }
} }
if plus || goSyntax { if plus || p.fmt.sharpV {
if f := t.Field(i); f.Name != "" { if f := t.Field(i); f.Name != "" {
p.buf.WriteString(f.Name) p.buf.WriteString(f.Name)
p.buf.WriteByte(':') p.buf.WriteByte(':')
} }
} }
p.printValue(getField(v, i), verb, plus, goSyntax, depth+1) p.printValue(getField(v, i), verb, plus, depth+1)
} }
p.buf.WriteByte('}') p.buf.WriteByte('}')
case reflect.Interface: case reflect.Interface:
value := f.Elem() value := f.Elem()
if !value.IsValid() { if !value.IsValid() {
if goSyntax { if p.fmt.sharpV {
p.buf.WriteString(f.Type().String()) p.buf.WriteString(f.Type().String())
p.buf.Write(nilParenBytes) p.buf.Write(nilParenBytes)
} else { } else {
p.buf.Write(nilAngleBytes) p.buf.Write(nilAngleBytes)
} }
} else { } else {
wasString = p.printValue(value, verb, plus, goSyntax, depth+1) wasString = p.printValue(value, verb, plus, depth+1)
} }
case reflect.Array, reflect.Slice: case reflect.Array, reflect.Slice:
// Byte slices are special: // Byte slices are special:
...@@ -947,11 +958,11 @@ BigSwitch: ...@@ -947,11 +958,11 @@ BigSwitch:
bytes[i] = byte(f.Index(i).Uint()) bytes[i] = byte(f.Index(i).Uint())
} }
} }
p.fmtBytes(bytes, verb, goSyntax, typ, depth) p.fmtBytes(bytes, verb, typ, depth)
wasString = verb == 's' wasString = verb == 's'
break break
} }
if goSyntax { if p.fmt.sharpV {
p.buf.WriteString(value.Type().String()) p.buf.WriteString(value.Type().String())
if f.Kind() == reflect.Slice && f.IsNil() { if f.Kind() == reflect.Slice && f.IsNil() {
p.buf.WriteString("(nil)") p.buf.WriteString("(nil)")
...@@ -963,15 +974,15 @@ BigSwitch: ...@@ -963,15 +974,15 @@ BigSwitch:
} }
for i := 0; i < f.Len(); i++ { for i := 0; i < f.Len(); i++ {
if i > 0 { if i > 0 {
if goSyntax { if p.fmt.sharpV {
p.buf.Write(commaSpaceBytes) p.buf.Write(commaSpaceBytes)
} else { } else {
p.buf.WriteByte(' ') p.buf.WriteByte(' ')
} }
} }
p.printValue(f.Index(i), verb, plus, goSyntax, depth+1) p.printValue(f.Index(i), verb, plus, depth+1)
} }
if goSyntax { if p.fmt.sharpV {
p.buf.WriteByte('}') p.buf.WriteByte('}')
} else { } else {
p.buf.WriteByte(']') p.buf.WriteByte(']')
...@@ -984,17 +995,17 @@ BigSwitch: ...@@ -984,17 +995,17 @@ BigSwitch:
switch a := f.Elem(); a.Kind() { switch a := f.Elem(); a.Kind() {
case reflect.Array, reflect.Slice: case reflect.Array, reflect.Slice:
p.buf.WriteByte('&') p.buf.WriteByte('&')
p.printValue(a, verb, plus, goSyntax, depth+1) p.printValue(a, verb, plus, depth+1)
break BigSwitch break BigSwitch
case reflect.Struct: case reflect.Struct:
p.buf.WriteByte('&') p.buf.WriteByte('&')
p.printValue(a, verb, plus, goSyntax, depth+1) p.printValue(a, verb, plus, depth+1)
break BigSwitch break BigSwitch
} }
} }
fallthrough fallthrough
case reflect.Chan, reflect.Func, reflect.UnsafePointer: case reflect.Chan, reflect.Func, reflect.UnsafePointer:
p.fmtPointer(value, verb, goSyntax) p.fmtPointer(value, verb)
default: default:
p.unknownType(f) p.unknownType(f)
} }
...@@ -1160,9 +1171,13 @@ func (p *pp) doPrintf(format string, a []interface{}) { ...@@ -1160,9 +1171,13 @@ func (p *pp) doPrintf(format string, a []interface{}) {
arg := a[argNum] arg := a[argNum]
argNum++ argNum++
goSyntax := c == 'v' && p.fmt.sharp if c == 'v' && p.fmt.sharp {
// Go syntax. Set the flag in the fmt and clear the sharp flag.
p.fmt.sharp = false
p.fmt.sharpV = true
}
plus := c == 'v' && p.fmt.plus plus := c == 'v' && p.fmt.plus
p.printArg(arg, c, plus, goSyntax, 0) p.printArg(arg, c, plus, 0)
} }
// Check for extra arguments unless the call accessed the arguments // Check for extra arguments unless the call accessed the arguments
...@@ -1176,7 +1191,7 @@ func (p *pp) doPrintf(format string, a []interface{}) { ...@@ -1176,7 +1191,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
p.buf.WriteString(reflect.TypeOf(arg).String()) p.buf.WriteString(reflect.TypeOf(arg).String())
p.buf.WriteByte('=') p.buf.WriteByte('=')
} }
p.printArg(arg, 'v', false, false, 0) p.printArg(arg, 'v', false, 0)
if argNum+1 < len(a) { if argNum+1 < len(a) {
p.buf.Write(commaSpaceBytes) p.buf.Write(commaSpaceBytes)
} }
...@@ -1197,7 +1212,7 @@ func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) { ...@@ -1197,7 +1212,7 @@ func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
p.buf.WriteByte(' ') p.buf.WriteByte(' ')
} }
} }
prevString = p.printArg(arg, 'v', false, false, 0) prevString = p.printArg(arg, 'v', false, 0)
} }
if addnewline { if addnewline {
p.buf.WriteByte('\n') p.buf.WriteByte('\n')
......
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