diff options
Diffstat (limited to 'src/pkg/fmt/print.go')
-rw-r--r-- | src/pkg/fmt/print.go | 417 |
1 files changed, 255 insertions, 162 deletions
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go index 738734908..3b7d3464e 100644 --- a/src/pkg/fmt/print.go +++ b/src/pkg/fmt/print.go @@ -6,11 +6,13 @@ package fmt import ( "bytes" + "errors" "io" "os" "reflect" + "sync" "unicode" - "utf8" + "unicode/utf8" ) // Some constants in the form of bytes, to avoid string overhead. @@ -36,7 +38,7 @@ var ( // the flags and options for the operand's format specifier. type State interface { // Write is the function to call to emit formatted output to be printed. - Write(b []byte) (ret int, err os.Error) + Write(b []byte) (ret int, err error) // Width returns the value of the width option and whether it has been set. Width() (wid int, ok bool) // Precision returns the value of the precision option and whether it has been set. @@ -50,7 +52,7 @@ type State interface { // The implementation of Format may call Sprintf or Fprintf(f) etc. // to generate its output. type Formatter interface { - Format(f State, c int) + Format(f State, c rune) } // Stringer is implemented by any value that has a String method, @@ -72,40 +74,49 @@ type GoStringer interface { type pp struct { n int panicking bool + erroring bool // printing an error condition buf bytes.Buffer - runeBuf [utf8.UTFMax]byte - fmt fmt + // field holds the current item, as an interface{}. + field interface{} + // value holds the current item, as a reflect.Value, and will be + // the zero Value if the item has not been reflected. + value reflect.Value + runeBuf [utf8.UTFMax]byte + fmt fmt } // A cache holds a set of reusable objects. -// The buffered channel holds the currently available objects. +// The slice is a stack (LIFO). // If more are needed, the cache creates them by calling new. type cache struct { - saved chan interface{} + mu sync.Mutex + saved []interface{} new func() interface{} } func (c *cache) put(x interface{}) { - select { - case c.saved <- x: - // saved in cache - default: - // discard + c.mu.Lock() + if len(c.saved) < cap(c.saved) { + c.saved = append(c.saved, x) } + c.mu.Unlock() } func (c *cache) get() interface{} { - select { - case x := <-c.saved: - return x // reused from cache - default: + c.mu.Lock() + n := len(c.saved) + if n == 0 { + c.mu.Unlock() return c.new() } - panic("not reached") + x := c.saved[n-1] + c.saved = c.saved[0 : n-1] + c.mu.Unlock() + return x } func newCache(f func() interface{}) *cache { - return &cache{make(chan interface{}, 100), f} + return &cache{saved: make([]interface{}, 0, 100), new: f} } var ppFree = newCache(func() interface{} { return new(pp) }) @@ -114,6 +125,7 @@ var ppFree = newCache(func() interface{} { return new(pp) }) func newPrinter() *pp { p := ppFree.get().(*pp) p.panicking = false + p.erroring = false p.fmt.init(&p.buf) return p } @@ -125,6 +137,8 @@ func (p *pp) free() { return } p.buf.Reset() + p.field = nil + p.value = reflect.Value{} ppFree.put(p) } @@ -148,13 +162,13 @@ func (p *pp) Flag(b int) bool { return false } -func (p *pp) add(c int) { +func (p *pp) add(c rune) { p.buf.WriteRune(c) } // Implement Write so we can call Fprintf on a pp (through State), for // recursive use in custom verbs. -func (p *pp) Write(b []byte) (ret int, err os.Error) { +func (p *pp) Write(b []byte) (ret int, err error) { return p.buf.Write(b) } @@ -162,7 +176,7 @@ func (p *pp) Write(b []byte) (ret int, err os.Error) { // Fprintf formats according to a format specifier and writes to w. // It returns the number of bytes written and any write error encountered. -func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err os.Error) { +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { p := newPrinter() p.doPrintf(format, a) n64, err := p.buf.WriteTo(w) @@ -172,7 +186,7 @@ func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err os.Error) // Printf formats according to a format specifier and writes to standard output. // It returns the number of bytes written and any write error encountered. -func Printf(format string, a ...interface{}) (n int, err os.Error) { +func Printf(format string, a ...interface{}) (n int, err error) { return Fprintf(os.Stdout, format, a...) } @@ -186,9 +200,9 @@ func Sprintf(format string, a ...interface{}) string { } // Errorf formats according to a format specifier and returns the string -// converted to an os.ErrorString, which satisfies the os.Error interface. -func Errorf(format string, a ...interface{}) os.Error { - return os.NewError(Sprintf(format, a...)) +// as a value that satisfies error. +func Errorf(format string, a ...interface{}) error { + return errors.New(Sprintf(format, a...)) } // These routines do not take a format string @@ -196,7 +210,7 @@ func Errorf(format string, a ...interface{}) os.Error { // Fprint formats using the default formats for its operands and writes to w. // Spaces are added between operands when neither is a string. // It returns the number of bytes written and any write error encountered. -func Fprint(w io.Writer, a ...interface{}) (n int, err os.Error) { +func Fprint(w io.Writer, a ...interface{}) (n int, err error) { p := newPrinter() p.doPrint(a, false, false) n64, err := p.buf.WriteTo(w) @@ -207,7 +221,7 @@ func Fprint(w io.Writer, a ...interface{}) (n int, err os.Error) { // Print formats using the default formats for its operands and writes to standard output. // Spaces are added between operands when neither is a string. // It returns the number of bytes written and any write error encountered. -func Print(a ...interface{}) (n int, err os.Error) { +func Print(a ...interface{}) (n int, err error) { return Fprint(os.Stdout, a...) } @@ -228,7 +242,7 @@ func Sprint(a ...interface{}) string { // Fprintln formats using the default formats for its operands and writes to w. // Spaces are always added between operands and a newline is appended. // It returns the number of bytes written and any write error encountered. -func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) { +func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { p := newPrinter() p.doPrint(a, true, true) n64, err := p.buf.WriteTo(w) @@ -239,7 +253,7 @@ func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) { // Println formats using the default formats for its operands and writes to standard output. // Spaces are always added between operands and a newline is appended. // It returns the number of bytes written and any write error encountered. -func Println(a ...interface{}) (n int, err os.Error) { +func Println(a ...interface{}) (n int, err error) { return Fprintln(os.Stdout, a...) } @@ -258,10 +272,8 @@ func Sprintln(a ...interface{}) string { // the thing inside the interface, not the interface itself. func getField(v reflect.Value, i int) reflect.Value { val := v.Field(i) - if i := val; i.Kind() == reflect.Interface { - if inter := i.Interface(); inter != nil { - return reflect.ValueOf(inter) - } + if val.Kind() == reflect.Interface && !val.IsNil() { + val = val.Elem() } return val } @@ -288,41 +300,48 @@ func (p *pp) unknownType(v interface{}) { p.buf.WriteByte('?') } -func (p *pp) badVerb(verb int, val interface{}) { +func (p *pp) badVerb(verb rune) { + p.erroring = true p.add('%') p.add('!') p.add(verb) p.add('(') - if val == nil { - p.buf.Write(nilAngleBytes) - } else { - p.buf.WriteString(reflect.TypeOf(val).String()) + switch { + case p.field != nil: + p.buf.WriteString(reflect.TypeOf(p.field).String()) + p.add('=') + p.printField(p.field, 'v', false, false, 0) + case p.value.IsValid(): + p.buf.WriteString(p.value.Type().String()) p.add('=') - p.printField(val, 'v', false, false, 0) + p.printValue(p.value, 'v', false, false, 0) + default: + p.buf.Write(nilAngleBytes) } p.add(')') + p.erroring = false } -func (p *pp) fmtBool(v bool, verb int, value interface{}) { +func (p *pp) fmtBool(v bool, verb rune) { switch verb { case 't', 'v': p.fmt.fmt_boolean(v) default: - p.badVerb(verb, value) + p.badVerb(verb) } } // 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 + r := rune(c) // Check for overflow. + if int64(r) != c { + r = utf8.RuneError } - w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], rune) + w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], r) p.fmt.pad(p.runeBuf[0:w]) } -func (p *pp) fmtInt64(v int64, verb int, value interface{}) { +func (p *pp) fmtInt64(v int64, verb rune) { switch verb { case 'b': p.fmt.integer(v, 2, signed, ldigits) @@ -336,7 +355,7 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) { if 0 <= v && v <= unicode.MaxRune { p.fmt.fmt_qc(v) } else { - p.badVerb(verb, value) + p.badVerb(verb) } case 'x': p.fmt.integer(v, 16, signed, ldigits) @@ -345,7 +364,7 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) { case 'X': p.fmt.integer(v, 16, signed, udigits) default: - p.badVerb(verb, value) + p.badVerb(verb) } } @@ -380,7 +399,7 @@ func (p *pp) fmtUnicode(v int64) { p.fmt.sharp = sharp } -func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) { +func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) { switch verb { case 'b': p.fmt.integer(int64(v), 2, unsigned, ldigits) @@ -400,7 +419,7 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) { if 0 <= v && v <= unicode.MaxRune { p.fmt.fmt_qc(int64(v)) } else { - p.badVerb(verb, value) + p.badVerb(verb) } case 'x': p.fmt.integer(int64(v), 16, unsigned, ldigits) @@ -409,11 +428,11 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) { case 'U': p.fmtUnicode(int64(v)) default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtFloat32(v float32, verb int, value interface{}) { +func (p *pp) fmtFloat32(v float32, verb rune) { switch verb { case 'b': p.fmt.fmt_fb32(v) @@ -428,11 +447,11 @@ func (p *pp) fmtFloat32(v float32, verb int, value interface{}) { case 'G': p.fmt.fmt_G32(v) default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtFloat64(v float64, verb int, value interface{}) { +func (p *pp) fmtFloat64(v float64, verb rune) { switch verb { case 'b': p.fmt.fmt_fb64(v) @@ -447,33 +466,33 @@ func (p *pp) fmtFloat64(v float64, verb int, value interface{}) { case 'G': p.fmt.fmt_G64(v) default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) { +func (p *pp) fmtComplex64(v complex64, verb rune) { 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) + p.badVerb(verb) } } -func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) { +func (p *pp) fmtComplex128(v complex128, verb rune) { 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) + p.badVerb(verb) } } -func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) { +func (p *pp) fmtString(v string, verb rune, goSyntax bool) { switch verb { case 'v': if goSyntax { @@ -484,17 +503,17 @@ func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) { case 's': p.fmt.fmt_s(v) case 'x': - p.fmt.fmt_sx(v) + p.fmt.fmt_sx(v, ldigits) case 'X': - p.fmt.fmt_sX(v) + p.fmt.fmt_sx(v, udigits) case 'q': p.fmt.fmt_q(v) default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) { +func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) { if verb == 'v' || verb == 'd' { if goSyntax { p.buf.Write(bytesBytes) @@ -523,28 +542,28 @@ func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interf case 's': p.fmt.fmt_s(s) case 'x': - p.fmt.fmt_sx(s) + p.fmt.fmt_sx(s, ldigits) case 'X': - p.fmt.fmt_sX(s) + p.fmt.fmt_sx(s, udigits) case 'q': p.fmt.fmt_q(s) default: - p.badVerb(verb, value) + p.badVerb(verb) } } -func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) { +func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) { var u uintptr switch value.Kind() { case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer: u = value.Pointer() default: - p.badVerb(verb, field) + p.badVerb(verb) return } if goSyntax { p.add('(') - p.buf.WriteString(reflect.TypeOf(field).String()) + p.buf.WriteString(value.Type().String()) p.add(')') p.add('(') if u == 0 { @@ -565,12 +584,12 @@ var ( uintptrBits = reflect.TypeOf(uintptr(0)).Bits() ) -func (p *pp) catchPanic(val interface{}, verb int) { +func (p *pp) catchPanic(field interface{}, verb rune) { if err := recover(); err != nil { // If it's a nil pointer, just say "<nil>". The likeliest causes are a // Stringer that fails to guard against nil or a nil pointer for a // value receiver, and in either case, "<nil>" is a nice result. - if v := reflect.ValueOf(val); v.Kind() == reflect.Ptr && v.IsNil() { + if v := reflect.ValueOf(field); v.Kind() == reflect.Ptr && v.IsNil() { p.buf.Write(nilAngleBytes) return } @@ -590,16 +609,77 @@ func (p *pp) catchPanic(val interface{}, verb int) { } } -func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) { +func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString, handled bool) { + if p.erroring { + return + } + // Is it a Formatter? + if formatter, ok := p.field.(Formatter); ok { + handled = true + wasString = false + defer p.catchPanic(p.field, verb) + formatter.Format(p, verb) + return + } + // Must not touch flags before Formatter looks at them. + if plus { + p.fmt.plus = false + } + + // If we're doing Go syntax and the field knows how to supply it, take care of it now. + if goSyntax { + p.fmt.sharp = false + if stringer, ok := p.field.(GoStringer); ok { + wasString = false + handled = true + defer p.catchPanic(p.field, verb) + // Print the result of GoString unadorned. + p.fmtString(stringer.GoString(), 's', false) + return + } + } else { + // If a string is acceptable according to the format, see if + // the value satisfies one of the string-valued interfaces. + // Println etc. set verb to %v, which is "stringable". + switch verb { + case 'v', 's', 'x', 'X', 'q': + // Is it an error or Stringer? + // The duplication in the bodies is necessary: + // setting wasString and handled, and deferring catchPanic, + // must happen before calling the method. + switch v := p.field.(type) { + case error: + wasString = false + handled = true + defer p.catchPanic(p.field, verb) + p.printField(v.Error(), verb, plus, false, depth) + return + + case Stringer: + wasString = false + handled = true + defer p.catchPanic(p.field, verb) + p.printField(v.String(), verb, plus, false, depth) + return + } + } + } + handled = false + return +} + +func (p *pp) printField(field interface{}, verb rune, plus, goSyntax bool, depth int) (wasString bool) { if field == nil { if verb == 'T' || verb == 'v' { p.buf.Write(nilAngleBytes) } else { - p.badVerb(verb, field) + p.badVerb(verb) } return false } + p.field = field + p.value = reflect.Value{} // Special processing considerations. // %T (the value's type) and %p (its address) are special; we always do them first. switch verb { @@ -607,124 +687,131 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth p.printField(reflect.TypeOf(field).String(), 's', false, false, 0) return false case 'p': - p.fmtPointer(field, reflect.ValueOf(field), verb, goSyntax) + p.fmtPointer(reflect.ValueOf(field), verb, goSyntax) return false } - // Is it a Formatter? - if formatter, ok := field.(Formatter); ok { - defer p.catchPanic(field, verb) - formatter.Format(p, verb) - return false // this value is not a string - } - // Must not touch flags before Formatter looks at them. - if plus { - p.fmt.plus = false - } - // If we're doing Go syntax and the field knows how to supply it, take care of it now. - if goSyntax { - p.fmt.sharp = false - if stringer, ok := field.(GoStringer); ok { - defer p.catchPanic(field, verb) - // Print the result of GoString unadorned. - p.fmtString(stringer.GoString(), 's', false, field) - return false // this value is not a string - } - } else { - // Is it a Stringer? - if stringer, ok := field.(Stringer); ok { - defer p.catchPanic(field, verb) - p.printField(stringer.String(), verb, plus, false, depth) - return false // this value is not a string - } + if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled { + return wasString } // Some types can be done without reflection. switch f := field.(type) { case bool: - p.fmtBool(f, verb, field) - return false + p.fmtBool(f, verb) case float32: - p.fmtFloat32(f, verb, field) - return false + p.fmtFloat32(f, verb) case float64: - p.fmtFloat64(f, verb, field) - return false + p.fmtFloat64(f, verb) case complex64: - p.fmtComplex64(complex64(f), verb, field) - return false + p.fmtComplex64(complex64(f), verb) case complex128: - p.fmtComplex128(f, verb, field) - return false + p.fmtComplex128(f, verb) case int: - p.fmtInt64(int64(f), verb, field) - return false + p.fmtInt64(int64(f), verb) case int8: - p.fmtInt64(int64(f), verb, field) - return false + p.fmtInt64(int64(f), verb) case int16: - p.fmtInt64(int64(f), verb, field) - return false + p.fmtInt64(int64(f), verb) case int32: - p.fmtInt64(int64(f), verb, field) - return false + p.fmtInt64(int64(f), verb) case int64: - p.fmtInt64(f, verb, field) - return false + p.fmtInt64(f, verb) case uint: - p.fmtUint64(uint64(f), verb, goSyntax, field) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint8: - p.fmtUint64(uint64(f), verb, goSyntax, field) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint16: - p.fmtUint64(uint64(f), verb, goSyntax, field) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint32: - p.fmtUint64(uint64(f), verb, goSyntax, field) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint64: - p.fmtUint64(f, verb, goSyntax, field) - return false + p.fmtUint64(f, verb, goSyntax) case uintptr: - p.fmtUint64(uint64(f), verb, goSyntax, field) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case string: - p.fmtString(f, verb, goSyntax, field) - return verb == 's' || verb == 'v' + p.fmtString(f, verb, goSyntax) + wasString = verb == 's' || verb == 'v' case []byte: - p.fmtBytes(f, verb, goSyntax, depth, field) - return verb == 's' + p.fmtBytes(f, verb, goSyntax, depth) + wasString = verb == 's' + default: + // Need to use reflection + return p.printReflectValue(reflect.ValueOf(field), verb, plus, goSyntax, depth) } + p.field = nil + return +} - // Need to use reflection - value := reflect.ValueOf(field) +// printValue is like printField 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) { + if !value.IsValid() { + if verb == 'T' || verb == 'v' { + p.buf.Write(nilAngleBytes) + } else { + p.badVerb(verb) + } + return false + } + + // Special processing considerations. + // %T (the value's type) and %p (its address) are special; we always do them first. + switch verb { + case 'T': + p.printField(value.Type().String(), 's', false, false, 0) + return false + case 'p': + p.fmtPointer(value, verb, goSyntax) + return false + } + + // Handle values with special methods. + // Call always, even when field == nil, because handleMethods clears p.fmt.plus for us. + p.field = nil // Make sure it's cleared, for safety. + if value.CanInterface() { + p.field = value.Interface() + } + if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled { + return wasString + } + + return p.printReflectValue(value, verb, plus, goSyntax, depth) +} +// printReflectValue is the fallback for both printField and printValue. +// It uses reflect to print the value. +func (p *pp) printReflectValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) { + oldValue := p.value + p.value = value BigSwitch: switch f := value; f.Kind() { case reflect.Bool: - p.fmtBool(f.Bool(), verb, field) + p.fmtBool(f.Bool(), verb) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p.fmtInt64(f.Int(), verb, field) + p.fmtInt64(f.Int(), verb) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p.fmtUint64(uint64(f.Uint()), verb, goSyntax, field) + p.fmtUint64(uint64(f.Uint()), verb, goSyntax) case reflect.Float32, reflect.Float64: if f.Type().Size() == 4 { - p.fmtFloat32(float32(f.Float()), verb, field) + p.fmtFloat32(float32(f.Float()), verb) } else { - p.fmtFloat64(float64(f.Float()), verb, field) + p.fmtFloat64(float64(f.Float()), verb) } case reflect.Complex64, reflect.Complex128: if f.Type().Size() == 8 { - p.fmtComplex64(complex64(f.Complex()), verb, field) + p.fmtComplex64(complex64(f.Complex()), verb) } else { - p.fmtComplex128(complex128(f.Complex()), verb, field) + p.fmtComplex128(complex128(f.Complex()), verb) } case reflect.String: - p.fmtString(f.String(), verb, goSyntax, field) + p.fmtString(f.String(), verb, goSyntax) case reflect.Map: if goSyntax { p.buf.WriteString(f.Type().String()) + if f.IsNil() { + p.buf.WriteString("(nil)") + break + } p.buf.WriteByte('{') } else { p.buf.Write(mapBytes) @@ -738,9 +825,9 @@ BigSwitch: p.buf.WriteByte(' ') } } - p.printField(key.Interface(), verb, plus, goSyntax, depth+1) + p.printValue(key, verb, plus, goSyntax, depth+1) p.buf.WriteByte(':') - p.printField(f.MapIndex(key).Interface(), verb, plus, goSyntax, depth+1) + p.printValue(f.MapIndex(key), verb, plus, goSyntax, depth+1) } if goSyntax { p.buf.WriteByte('}') @@ -749,7 +836,7 @@ BigSwitch: } case reflect.Struct: if goSyntax { - p.buf.WriteString(reflect.TypeOf(field).String()) + p.buf.WriteString(value.Type().String()) } p.add('{') v := f @@ -768,20 +855,20 @@ BigSwitch: p.buf.WriteByte(':') } } - p.printField(getField(v, i).Interface(), verb, plus, goSyntax, depth+1) + p.printValue(getField(v, i), verb, plus, goSyntax, depth+1) } p.buf.WriteByte('}') case reflect.Interface: value := f.Elem() if !value.IsValid() { if goSyntax { - p.buf.WriteString(reflect.TypeOf(field).String()) + p.buf.WriteString(f.Type().String()) p.buf.Write(nilParenBytes) } else { p.buf.Write(nilAngleBytes) } } else { - return p.printField(value.Interface(), verb, plus, goSyntax, depth+1) + wasString = p.printValue(value, verb, plus, goSyntax, depth+1) } case reflect.Array, reflect.Slice: // Byte slices are special. @@ -797,11 +884,16 @@ BigSwitch: for i := range bytes { bytes[i] = byte(f.Index(i).Uint()) } - p.fmtBytes(bytes, verb, goSyntax, depth, field) - return verb == 's' + p.fmtBytes(bytes, verb, goSyntax, depth) + wasString = verb == 's' + break } if goSyntax { - p.buf.WriteString(reflect.TypeOf(field).String()) + p.buf.WriteString(value.Type().String()) + if f.Kind() == reflect.Slice && f.IsNil() { + p.buf.WriteString("(nil)") + break + } p.buf.WriteByte('{') } else { p.buf.WriteByte('[') @@ -814,7 +906,7 @@ BigSwitch: p.buf.WriteByte(' ') } } - p.printField(f.Index(i).Interface(), verb, plus, goSyntax, depth+1) + p.printValue(f.Index(i), verb, plus, goSyntax, depth+1) } if goSyntax { p.buf.WriteByte('}') @@ -829,17 +921,17 @@ BigSwitch: switch a := f.Elem(); a.Kind() { case reflect.Array, reflect.Slice: p.buf.WriteByte('&') - p.printField(a.Interface(), verb, plus, goSyntax, depth+1) + p.printValue(a, verb, plus, goSyntax, depth+1) break BigSwitch case reflect.Struct: p.buf.WriteByte('&') - p.printField(a.Interface(), verb, plus, goSyntax, depth+1) + p.printValue(a, verb, plus, goSyntax, depth+1) break BigSwitch } } if goSyntax { p.buf.WriteByte('(') - p.buf.WriteString(reflect.TypeOf(field).String()) + p.buf.WriteString(value.Type().String()) p.buf.WriteByte(')') p.buf.WriteByte('(') if v == 0 { @@ -856,11 +948,12 @@ BigSwitch: } p.fmt0x64(uint64(v), true) case reflect.Chan, reflect.Func, reflect.UnsafePointer: - p.fmtPointer(field, value, verb, goSyntax) + p.fmtPointer(value, verb, goSyntax) default: p.unknownType(f) } - return false + p.value = oldValue + return wasString } // intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int. |