diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go index ba50b932838..710baeec1d2 100644 --- a/src/pkg/fmt/print.go +++ b/src/pkg/fmt/print.go @@ -74,6 +74,8 @@ type pp struct { n int panicking bool buf bytes.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 @@ -132,6 +134,7 @@ func (p *pp) free() { return } p.buf.Reset() + p.field = nil p.value = reflect.Value{} ppFree.put(p) } @@ -294,16 +297,16 @@ func (p *pp) unknownType(v interface{}) { p.buf.WriteByte('?') } -func (p *pp) badVerb(verb int, val interface{}) { +func (p *pp) badVerb(verb int) { 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) + p.printField(p.field, 'v', false, false, 0) case p.value.IsValid(): p.buf.WriteString(p.value.Type().String()) p.add('=') @@ -314,12 +317,12 @@ func (p *pp) badVerb(verb int, val interface{}) { p.add(')') } -func (p *pp) fmtBool(v bool, verb int, value interface{}) { +func (p *pp) fmtBool(v bool, verb int) { switch verb { case 't', 'v': p.fmt.fmt_boolean(v) default: - p.badVerb(verb, value) + p.badVerb(verb) } } @@ -333,7 +336,7 @@ func (p *pp) fmtC(c int64) { p.fmt.pad(p.runeBuf[0:w]) } -func (p *pp) fmtInt64(v int64, verb int, value interface{}) { +func (p *pp) fmtInt64(v int64, verb int) { switch verb { case 'b': p.fmt.integer(v, 2, signed, ldigits) @@ -347,7 +350,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) @@ -356,7 +359,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) } } @@ -391,7 +394,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 int, goSyntax bool) { switch verb { case 'b': p.fmt.integer(int64(v), 2, unsigned, ldigits) @@ -411,7 +414,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) @@ -420,11 +423,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 int) { switch verb { case 'b': p.fmt.fmt_fb32(v) @@ -439,11 +442,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 int) { switch verb { case 'b': p.fmt.fmt_fb64(v) @@ -458,33 +461,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 int) { 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 int) { 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 int, goSyntax bool) { switch verb { case 'v': if goSyntax { @@ -501,11 +504,11 @@ func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) { 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 int, goSyntax bool, depth int) { if verb == 'v' || verb == 'd' { if goSyntax { p.buf.Write(bytesBytes) @@ -540,17 +543,17 @@ func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interf 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 int, 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 { @@ -576,12 +579,12 @@ var ( uintptrBits = reflect.TypeOf(uintptr(0)).Bits() ) -func (p *pp) catchPanic(val interface{}, verb int) { +func (p *pp) catchPanic(field interface{}, verb int) { if err := recover(); err != nil { // If it's a nil pointer, just say "". The likeliest causes are a // Stringer that fails to guard against nil or a nil pointer for a // value receiver, and in either case, "" 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 } @@ -601,12 +604,12 @@ 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 int, plus, goSyntax bool, depth int) (wasString, handled bool) { // 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 } @@ -618,20 +621,20 @@ 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) + p.fmtString(stringer.GoString(), 's', false) return } } else { // Is it a Stringer? - if stringer, ok := field.(Stringer); ok { + if stringer, ok := p.field.(Stringer); ok { wasString = false handled = true - defer p.catchPanic(field, verb) + defer p.catchPanic(p.field, verb) p.printField(stringer.String(), verb, plus, false, depth) return } @@ -645,11 +648,13 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth 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 { @@ -657,74 +662,60 @@ 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) - 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) } - - // 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. @@ -733,7 +724,7 @@ func (p *pp) printValue(value reflect.Value, verb int, plus, goSyntax bool, dept if verb == 'T' || verb == 'v' { p.buf.Write(nilAngleBytes) } else { - p.badVerb(verb, nil) + p.badVerb(verb) } return false } @@ -745,17 +736,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 } @@ -770,25 +761,25 @@ func (p *pp) printReflectValue(value reflect.Value, verb int, plus, goSyntax boo BigSwitch: switch f := value; f.Kind() { case reflect.Bool: - p.fmtBool(f.Bool(), verb, nil) + p.fmtBool(f.Bool(), verb) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - p.fmtInt64(f.Int(), verb, nil) + 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) + p.fmtUint64(uint64(f.Uint()), verb, goSyntax) case reflect.Float32, reflect.Float64: if f.Type().Size() == 4 { - p.fmtFloat32(float32(f.Float()), verb, nil) + p.fmtFloat32(float32(f.Float()), verb) } else { - p.fmtFloat64(float64(f.Float()), verb, nil) + p.fmtFloat64(float64(f.Float()), verb) } case reflect.Complex64, reflect.Complex128: if f.Type().Size() == 8 { - p.fmtComplex64(complex64(f.Complex()), verb, nil) + p.fmtComplex64(complex64(f.Complex()), verb) } else { - p.fmtComplex128(complex128(f.Complex()), verb, nil) + p.fmtComplex128(complex128(f.Complex()), verb) } case reflect.String: - p.fmtString(f.String(), verb, goSyntax, nil) + p.fmtString(f.String(), verb, goSyntax) case reflect.Map: if goSyntax { p.buf.WriteString(f.Type().String()) @@ -864,7 +855,7 @@ BigSwitch: for i := range bytes { bytes[i] = byte(f.Index(i).Uint()) } - p.fmtBytes(bytes, verb, goSyntax, depth, nil) + p.fmtBytes(bytes, verb, goSyntax, depth) wasString = verb == 's' break } @@ -924,7 +915,7 @@ BigSwitch: } p.fmt0x64(uint64(v), true) case reflect.Chan, reflect.Func, reflect.UnsafePointer: - p.fmtPointer(nil, value, verb, goSyntax) + p.fmtPointer(value, verb, goSyntax) default: p.unknownType(f) }