diff options
Diffstat (limited to 'src/pkg/fmt/print.go')
| -rw-r--r-- | src/pkg/fmt/print.go | 414 |
1 files changed, 238 insertions, 176 deletions
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go index 136aebd33..13438243c 100644 --- a/src/pkg/fmt/print.go +++ b/src/pkg/fmt/print.go @@ -5,12 +5,12 @@ package fmt import ( - "bytes" + "errors" "io" "os" "reflect" - "unicode" - "utf8" + "sync" + "unicode/utf8" ) // Some constants in the form of bytes, to avoid string overhead. @@ -36,7 +36,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 +50,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, @@ -69,43 +69,86 @@ type GoStringer interface { GoString() string } +// Use simple []byte instead of bytes.Buffer to avoid large dependency. +type buffer []byte + +func (b *buffer) Write(p []byte) (n int, err error) { + *b = append(*b, p...) + return len(p), nil +} + +func (b *buffer) WriteString(s string) (n int, err error) { + *b = append(*b, s...) + return len(s), nil +} + +func (b *buffer) WriteByte(c byte) error { + *b = append(*b, c) + return nil +} + +func (bp *buffer) WriteRune(r rune) error { + if r < utf8.RuneSelf { + *bp = append(*bp, byte(r)) + return nil + } + + b := *bp + n := len(b) + for n+utf8.UTFMax > cap(b) { + b = append(b, 0) + } + w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r) + *bp = b[:n+w] + return nil +} + type pp struct { n int panicking bool - buf bytes.Buffer - runeBuf [utf8.UTFMax]byte - fmt fmt + erroring bool // printing an error condition + buf buffer + // 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 +157,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 } @@ -121,10 +165,12 @@ func newPrinter() *pp { // Save used pp structs in ppFree; avoids an allocation per invocation. func (p *pp) free() { // Don't hold on to pp structs with large buffers. - if cap(p.buf.Bytes()) > 1024 { + if cap(p.buf) > 1024 { return } - p.buf.Reset() + p.buf = p.buf[:0] + p.field = nil + p.value = reflect.Value{} ppFree.put(p) } @@ -148,13 +194,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,17 +208,17 @@ 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) + n64, err := w.Write(p.buf) p.free() return int(n64), err } // 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...) } @@ -180,15 +226,15 @@ func Printf(format string, a ...interface{}) (n int, err os.Error) { func Sprintf(format string, a ...interface{}) string { p := newPrinter() p.doPrintf(format, a) - s := p.buf.String() + s := string(p.buf) p.free() return s } // 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,10 +242,10 @@ 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) + n64, err := w.Write(p.buf) p.free() return int(n64), err } @@ -207,7 +253,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...) } @@ -216,7 +262,7 @@ func Print(a ...interface{}) (n int, err os.Error) { func Sprint(a ...interface{}) string { p := newPrinter() p.doPrint(a, false, false) - s := p.buf.String() + s := string(p.buf) p.free() return s } @@ -228,10 +274,10 @@ 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) + n64, err := w.Write(p.buf) p.free() return int(n64), err } @@ -239,7 +285,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...) } @@ -248,7 +294,7 @@ func Println(a ...interface{}) (n int, err os.Error) { func Sprintln(a ...interface{}) string { p := newPrinter() p.doPrint(a, true, true) - s := p.buf.String() + s := string(p.buf) p.free() return s } @@ -286,46 +332,48 @@ func (p *pp) unknownType(v interface{}) { p.buf.WriteByte('?') } -func (p *pp) badVerb(verb int, val interface{}, val1 reflect.Value) { +func (p *pp) badVerb(verb rune) { + p.erroring = true p.add('%') p.add('!') p.add(verb) p.add('(') switch { - case val != nil: - p.buf.WriteString(reflect.TypeOf(val).String()) + case p.field != nil: + p.buf.WriteString(reflect.TypeOf(p.field).String()) p.add('=') - p.printField(val, 'v', false, false, 0) - case val1.IsValid(): - p.buf.WriteString(val1.Type().String()) + p.printField(p.field, 'v', false, false, 0) + case p.value.IsValid(): + p.buf.WriteString(p.value.Type().String()) p.add('=') - p.printValue(val1, '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{}, value1 reflect.Value) { +func (p *pp) fmtBool(v bool, verb rune) { switch verb { case 't', 'v': p.fmt.fmt_boolean(v) default: - p.badVerb(verb, value, value1) + 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{}, value1 reflect.Value) { +func (p *pp) fmtInt64(v int64, verb rune) { switch verb { case 'b': p.fmt.integer(v, 2, signed, ldigits) @@ -336,10 +384,10 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}, value1 reflect.Value case 'o': p.fmt.integer(v, 8, signed, ldigits) case 'q': - if 0 <= v && v <= unicode.MaxRune { + if 0 <= v && v <= utf8.MaxRune { p.fmt.fmt_qc(v) } else { - p.badVerb(verb, value, value1) + p.badVerb(verb) } case 'x': p.fmt.integer(v, 16, signed, ldigits) @@ -348,7 +396,7 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}, value1 reflect.Value case 'X': p.fmt.integer(v, 16, signed, udigits) default: - p.badVerb(verb, value, value1) + p.badVerb(verb) } } @@ -383,7 +431,7 @@ func (p *pp) fmtUnicode(v int64) { p.fmt.sharp = sharp } -func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}, value1 reflect.Value) { +func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) { switch verb { case 'b': p.fmt.integer(int64(v), 2, unsigned, ldigits) @@ -400,10 +448,10 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}, val case 'o': p.fmt.integer(int64(v), 8, unsigned, ldigits) case 'q': - if 0 <= v && v <= unicode.MaxRune { + if 0 <= v && v <= utf8.MaxRune { p.fmt.fmt_qc(int64(v)) } else { - p.badVerb(verb, value, value1) + p.badVerb(verb) } case 'x': p.fmt.integer(int64(v), 16, unsigned, ldigits) @@ -412,11 +460,11 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}, val case 'U': p.fmtUnicode(int64(v)) default: - p.badVerb(verb, value, value1) + p.badVerb(verb) } } -func (p *pp) fmtFloat32(v float32, verb int, value interface{}, value1 reflect.Value) { +func (p *pp) fmtFloat32(v float32, verb rune) { switch verb { case 'b': p.fmt.fmt_fb32(v) @@ -431,11 +479,11 @@ func (p *pp) fmtFloat32(v float32, verb int, value interface{}, value1 reflect.V case 'G': p.fmt.fmt_G32(v) default: - p.badVerb(verb, value, value1) + p.badVerb(verb) } } -func (p *pp) fmtFloat64(v float64, verb int, value interface{}, value1 reflect.Value) { +func (p *pp) fmtFloat64(v float64, verb rune) { switch verb { case 'b': p.fmt.fmt_fb64(v) @@ -450,33 +498,33 @@ func (p *pp) fmtFloat64(v float64, verb int, value interface{}, value1 reflect.V case 'G': p.fmt.fmt_G64(v) default: - p.badVerb(verb, value, value1) + p.badVerb(verb) } } -func (p *pp) fmtComplex64(v complex64, verb int, value interface{}, value1 reflect.Value) { +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, value1) + p.badVerb(verb) } } -func (p *pp) fmtComplex128(v complex128, verb int, value interface{}, value1 reflect.Value) { +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, value1) + p.badVerb(verb) } } -func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}, value1 reflect.Value) { +func (p *pp) fmtString(v string, verb rune, goSyntax bool) { switch verb { case 'v': if goSyntax { @@ -487,17 +535,17 @@ func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}, val 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, value1) + p.badVerb(verb) } } -func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}, value1 reflect.Value) { +func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) { if verb == 'v' || verb == 'd' { if goSyntax { p.buf.Write(bytesBytes) @@ -526,25 +574,34 @@ 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, value1) + 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) { + switch verb { + case 'p', 'v', 'b', 'd', 'o', 'x', 'X': + // ok + default: + p.badVerb(verb) + return + } + 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, value) + p.badVerb(verb) return } + if goSyntax { p.add('(') p.buf.WriteString(value.Type().String()) @@ -556,6 +613,8 @@ func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSynt p.fmt0x64(uint64(u), true) } p.add(')') + } else if verb == 'v' && u == 0 { + p.buf.Write(nilAngleBytes) } else { p.fmt0x64(uint64(u), !p.fmt.sharp) } @@ -568,12 +627,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 } @@ -593,12 +652,15 @@ func (p *pp) catchPanic(val interface{}, verb int) { } } -func (p *pp) handleMethods(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString, handled 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 := field.(Formatter); ok { + if formatter, ok := p.field.(Formatter); ok { handled = true wasString = false - defer p.catchPanic(field, verb) + defer p.catchPanic(p.field, verb) formatter.Format(p, verb) return } @@ -610,38 +672,57 @@ func (p *pp) handleMethods(field interface{}, verb int, plus, goSyntax bool, dep // 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 { + if stringer, ok := p.field.(GoStringer); ok { wasString = false handled = true - defer p.catchPanic(field, verb) + defer p.catchPanic(p.field, verb) // Print the result of GoString unadorned. - p.fmtString(stringer.GoString(), 's', false, field, reflect.Value{}) + p.fmtString(stringer.GoString(), 's', false) return } } else { - // Is it a Stringer? - if stringer, ok := field.(Stringer); ok { - wasString = false - handled = true - defer p.catchPanic(field, verb) - p.printField(stringer.String(), verb, plus, false, depth) - return + // 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 int, plus, goSyntax bool, depth int) (wasString bool) { +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, reflect.Value{}) + 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 { @@ -649,83 +730,69 @@ 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 } - if wasString, handled := p.handleMethods(field, verb, plus, goSyntax, depth); handled { + 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, reflect.Value{}) - return false + p.fmtBool(f, verb) case float32: - p.fmtFloat32(f, verb, field, reflect.Value{}) - return false + p.fmtFloat32(f, verb) case float64: - p.fmtFloat64(f, verb, field, reflect.Value{}) - return false + p.fmtFloat64(f, verb) case complex64: - p.fmtComplex64(complex64(f), verb, field, reflect.Value{}) - return false + p.fmtComplex64(complex64(f), verb) case complex128: - p.fmtComplex128(f, verb, field, reflect.Value{}) - return false + p.fmtComplex128(f, verb) case int: - p.fmtInt64(int64(f), verb, field, reflect.Value{}) - return false + p.fmtInt64(int64(f), verb) case int8: - p.fmtInt64(int64(f), verb, field, reflect.Value{}) - return false + p.fmtInt64(int64(f), verb) case int16: - p.fmtInt64(int64(f), verb, field, reflect.Value{}) - return false + p.fmtInt64(int64(f), verb) case int32: - p.fmtInt64(int64(f), verb, field, reflect.Value{}) - return false + p.fmtInt64(int64(f), verb) case int64: - p.fmtInt64(f, verb, field, reflect.Value{}) - return false + p.fmtInt64(f, verb) case uint: - p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{}) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint8: - p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{}) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint16: - p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{}) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint32: - p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{}) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case uint64: - p.fmtUint64(f, verb, goSyntax, field, reflect.Value{}) - return false + p.fmtUint64(f, verb, goSyntax) case uintptr: - p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{}) - return false + p.fmtUint64(uint64(f), verb, goSyntax) case string: - p.fmtString(f, verb, goSyntax, field, reflect.Value{}) - return verb == 's' || verb == 'v' + p.fmtString(f, verb, goSyntax) + wasString = verb == 's' || verb == 'v' case []byte: - p.fmtBytes(f, verb, goSyntax, depth, field, reflect.Value{}) - 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) } - - // Need to use reflection - return p.printReflectValue(reflect.ValueOf(field), verb, plus, goSyntax, depth) + p.field = nil + return } // printValue is like printField but starts with a reflect value, not an interface{} value. -func (p *pp) printValue(value reflect.Value, verb int, plus, goSyntax bool, depth int) (wasString bool) { +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, nil, value) + p.badVerb(verb) } return false } @@ -737,17 +804,17 @@ func (p *pp) printValue(value reflect.Value, verb int, plus, goSyntax bool, dept p.printField(value.Type().String(), 's', false, false, 0) return false case 'p': - p.fmtPointer(nil, value, verb, goSyntax) + 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. - var field interface{} + p.field = nil // Make sure it's cleared, for safety. if value.CanInterface() { - field = value.Interface() + p.field = value.Interface() } - if wasString, handled := p.handleMethods(field, verb, plus, goSyntax, depth); handled { + if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled { return wasString } @@ -756,32 +823,38 @@ func (p *pp) printValue(value reflect.Value, verb int, plus, goSyntax bool, dept // printReflectValue is the fallback for both printField and printValue. // It uses reflect to print the value. -func (p *pp) printReflectValue(value reflect.Value, verb int, plus, goSyntax bool, depth int) (wasString bool) { +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, nil, value) + p.fmtBool(f.Bool(), verb) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p.fmtInt64(f.Int(), verb, nil, value) + 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, nil, value) + p.fmtUint64(uint64(f.Uint()), verb, goSyntax) case reflect.Float32, reflect.Float64: if f.Type().Size() == 4 { - p.fmtFloat32(float32(f.Float()), verb, nil, value) + p.fmtFloat32(float32(f.Float()), verb) } else { - p.fmtFloat64(float64(f.Float()), verb, nil, value) + p.fmtFloat64(float64(f.Float()), verb) } case reflect.Complex64, reflect.Complex128: if f.Type().Size() == 8 { - p.fmtComplex64(complex64(f.Complex()), verb, nil, value) + p.fmtComplex64(complex64(f.Complex()), verb) } else { - p.fmtComplex128(complex128(f.Complex()), verb, nil, value) + p.fmtComplex128(complex128(f.Complex()), verb) } case reflect.String: - p.fmtString(f.String(), verb, goSyntax, nil, value) + 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) @@ -832,13 +905,13 @@ BigSwitch: value := f.Elem() if !value.IsValid() { if goSyntax { - p.buf.WriteString(value.Type().String()) + p.buf.WriteString(f.Type().String()) p.buf.Write(nilParenBytes) } else { p.buf.Write(nilAngleBytes) } } else { - return p.printValue(value, verb, plus, goSyntax, depth+1) + wasString = p.printValue(value, verb, plus, goSyntax, depth+1) } case reflect.Array, reflect.Slice: // Byte slices are special. @@ -854,11 +927,16 @@ BigSwitch: for i := range bytes { bytes[i] = byte(f.Index(i).Uint()) } - p.fmtBytes(bytes, verb, goSyntax, depth, nil, value) - return verb == 's' + p.fmtBytes(bytes, verb, goSyntax, depth) + wasString = verb == 's' + break } if goSyntax { 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('[') @@ -894,30 +972,14 @@ BigSwitch: break BigSwitch } } - if goSyntax { - p.buf.WriteByte('(') - p.buf.WriteString(value.Type().String()) - p.buf.WriteByte(')') - p.buf.WriteByte('(') - if v == 0 { - p.buf.Write(nilBytes) - } else { - p.fmt0x64(uint64(v), true) - } - p.buf.WriteByte(')') - break - } - if v == 0 { - p.buf.Write(nilAngleBytes) - break - } - p.fmt0x64(uint64(v), true) + fallthrough case reflect.Chan, reflect.Func, reflect.UnsafePointer: - p.fmtPointer(nil, 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. |
