aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/fmt/print.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/fmt/print.go')
-rw-r--r--src/pkg/fmt/print.go245
1 files changed, 151 insertions, 94 deletions
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index c18a8ea38d..1042315ed9 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -259,10 +259,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
}
@@ -289,27 +287,32 @@ func (p *pp) unknownType(v interface{}) {
p.buf.WriteByte('?')
}
-func (p *pp) badVerb(verb int, val interface{}) {
+func (p *pp) badVerb(verb int, val interface{}, val1 reflect.Value) {
p.add('%')
p.add('!')
p.add(verb)
p.add('(')
- if val == nil {
- p.buf.Write(nilAngleBytes)
- } else {
+ switch {
+ case val != nil:
p.buf.WriteString(reflect.TypeOf(val).String())
p.add('=')
p.printField(val, 'v', false, false, 0)
+ case val1.IsValid():
+ p.buf.WriteString(val1.Type().String())
+ p.add('=')
+ p.printValue(val1, 'v', false, false, 0)
+ default:
+ p.buf.Write(nilAngleBytes)
}
p.add(')')
}
-func (p *pp) fmtBool(v bool, verb int, value interface{}) {
+func (p *pp) fmtBool(v bool, verb int, value interface{}, value1 reflect.Value) {
switch verb {
case 't', 'v':
p.fmt.fmt_boolean(v)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb, value, value1)
}
}
@@ -323,7 +326,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, value interface{}, value1 reflect.Value) {
switch verb {
case 'b':
p.fmt.integer(v, 2, signed, ldigits)
@@ -337,7 +340,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, value, value1)
}
case 'x':
p.fmt.integer(v, 16, signed, ldigits)
@@ -346,7 +349,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, value, value1)
}
}
@@ -376,7 +379,7 @@ func (p *pp) fmtUnicode(v int64) {
p.fmt.precPresent = precPresent
}
-func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
+func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}, value1 reflect.Value) {
switch verb {
case 'b':
p.fmt.integer(int64(v), 2, unsigned, ldigits)
@@ -396,7 +399,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, value, value1)
}
case 'x':
p.fmt.integer(int64(v), 16, unsigned, ldigits)
@@ -405,11 +408,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, value, value1)
}
}
-func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
+func (p *pp) fmtFloat32(v float32, verb int, value interface{}, value1 reflect.Value) {
switch verb {
case 'b':
p.fmt.fmt_fb32(v)
@@ -424,11 +427,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, value, value1)
}
}
-func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
+func (p *pp) fmtFloat64(v float64, verb int, value interface{}, value1 reflect.Value) {
switch verb {
case 'b':
p.fmt.fmt_fb64(v)
@@ -443,33 +446,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, value, value1)
}
}
-func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) {
+func (p *pp) fmtComplex64(v complex64, verb int, value interface{}, value1 reflect.Value) {
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, value, value1)
}
}
-func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) {
+func (p *pp) fmtComplex128(v complex128, verb int, value interface{}, value1 reflect.Value) {
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, value, value1)
}
}
-func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
+func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}, value1 reflect.Value) {
switch verb {
case 'v':
if goSyntax {
@@ -486,11 +489,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, value, value1)
}
}
-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, value interface{}, value1 reflect.Value) {
if verb == 'v' || verb == 'd' {
if goSyntax {
p.buf.Write(bytesBytes)
@@ -525,7 +528,7 @@ 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, value, value1)
}
}
@@ -535,12 +538,12 @@ func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSynt
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
u = value.Pointer()
default:
- p.badVerb(verb, field)
+ p.badVerb(verb, field, value)
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 {
@@ -561,12 +564,48 @@ var (
uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
)
+func (p *pp) handleMethods(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString, handled bool) {
+ // Is it a Formatter?
+ if formatter, ok := field.(Formatter); ok {
+ handled = true
+ wasString = false
+ 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 := field.(GoStringer); ok {
+ wasString = false
+ handled = true
+ // Print the result of GoString unadorned.
+ p.fmtString(stringer.GoString(), 's', false, field, reflect.Value{})
+ return
+ }
+ } else {
+ // Is it a Stringer?
+ if stringer, ok := field.(Stringer); ok {
+ wasString = false
+ handled = true
+ p.printField(stringer.String(), verb, plus, false, depth)
+ return
+ }
+ }
+ handled = false
+ return
+}
+
func (p *pp) printField(field interface{}, verb int, 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, field, reflect.Value{})
}
return false
}
@@ -581,115 +620,133 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
p.fmtPointer(field, reflect.ValueOf(field), verb, goSyntax)
return false
}
- // Is it a Formatter?
- if formatter, ok := field.(Formatter); ok {
- 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 {
- // 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 {
- p.printField(stringer.String(), verb, plus, false, depth)
- return false // this value is not a string
- }
+ if wasString, handled := p.handleMethods(field, 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)
+ p.fmtBool(f, verb, field, reflect.Value{})
return false
case float32:
- p.fmtFloat32(f, verb, field)
+ p.fmtFloat32(f, verb, field, reflect.Value{})
return false
case float64:
- p.fmtFloat64(f, verb, field)
+ p.fmtFloat64(f, verb, field, reflect.Value{})
return false
case complex64:
- p.fmtComplex64(complex64(f), verb, field)
+ p.fmtComplex64(complex64(f), verb, field, reflect.Value{})
return false
case complex128:
- p.fmtComplex128(f, verb, field)
+ p.fmtComplex128(f, verb, field, reflect.Value{})
return false
case int:
- p.fmtInt64(int64(f), verb, field)
+ p.fmtInt64(int64(f), verb, field, reflect.Value{})
return false
case int8:
- p.fmtInt64(int64(f), verb, field)
+ p.fmtInt64(int64(f), verb, field, reflect.Value{})
return false
case int16:
- p.fmtInt64(int64(f), verb, field)
+ p.fmtInt64(int64(f), verb, field, reflect.Value{})
return false
case int32:
- p.fmtInt64(int64(f), verb, field)
+ p.fmtInt64(int64(f), verb, field, reflect.Value{})
return false
case int64:
- p.fmtInt64(f, verb, field)
+ p.fmtInt64(f, verb, field, reflect.Value{})
return false
case uint:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
+ p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
return false
case uint8:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
+ p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
return false
case uint16:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
+ p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
return false
case uint32:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
+ p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
return false
case uint64:
- p.fmtUint64(f, verb, goSyntax, field)
+ p.fmtUint64(f, verb, goSyntax, field, reflect.Value{})
return false
case uintptr:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
+ p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
return false
case string:
- p.fmtString(f, verb, goSyntax, field)
+ p.fmtString(f, verb, goSyntax, field, reflect.Value{})
return verb == 's' || verb == 'v'
case []byte:
- p.fmtBytes(f, verb, goSyntax, depth, field)
+ p.fmtBytes(f, verb, goSyntax, depth, field, reflect.Value{})
return verb == 's'
}
// Need to use reflection
- value := reflect.ValueOf(field)
+ return p.printReflectValue(reflect.ValueOf(field), verb, plus, goSyntax, depth)
+}
+
+// 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) {
+ if !value.IsValid() {
+ if verb == 'T' || verb == 'v' {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.badVerb(verb, nil, value)
+ }
+ 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(nil, 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{}
+ if value.CanInterface() {
+ field = value.Interface()
+ }
+ if wasString, handled := p.handleMethods(field, 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 int, plus, goSyntax bool, depth int) (wasString bool) {
BigSwitch:
switch f := value; f.Kind() {
case reflect.Bool:
- p.fmtBool(f.Bool(), verb, field)
+ p.fmtBool(f.Bool(), verb, nil, value)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p.fmtInt64(f.Int(), verb, field)
+ p.fmtInt64(f.Int(), verb, nil, value)
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, nil, value)
case reflect.Float32, reflect.Float64:
if f.Type().Size() == 4 {
- p.fmtFloat32(float32(f.Float()), verb, field)
+ p.fmtFloat32(float32(f.Float()), verb, nil, value)
} else {
- p.fmtFloat64(float64(f.Float()), verb, field)
+ p.fmtFloat64(float64(f.Float()), verb, nil, value)
}
case reflect.Complex64, reflect.Complex128:
if f.Type().Size() == 8 {
- p.fmtComplex64(complex64(f.Complex()), verb, field)
+ p.fmtComplex64(complex64(f.Complex()), verb, nil, value)
} else {
- p.fmtComplex128(complex128(f.Complex()), verb, field)
+ p.fmtComplex128(complex128(f.Complex()), verb, nil, value)
}
case reflect.String:
- p.fmtString(f.String(), verb, goSyntax, field)
+ p.fmtString(f.String(), verb, goSyntax, nil, value)
case reflect.Map:
if goSyntax {
p.buf.WriteString(f.Type().String())
@@ -706,9 +763,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('}')
@@ -717,7 +774,7 @@ BigSwitch:
}
case reflect.Struct:
if goSyntax {
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(value.Type().String())
}
p.add('{')
v := f
@@ -736,20 +793,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(value.Type().String())
p.buf.Write(nilParenBytes)
} else {
p.buf.Write(nilAngleBytes)
}
} else {
- return p.printField(value.Interface(), verb, plus, goSyntax, depth+1)
+ return p.printValue(value, verb, plus, goSyntax, depth+1)
}
case reflect.Array, reflect.Slice:
// Byte slices are special.
@@ -765,11 +822,11 @@ BigSwitch:
for i := range bytes {
bytes[i] = byte(f.Index(i).Uint())
}
- p.fmtBytes(bytes, verb, goSyntax, depth, field)
+ p.fmtBytes(bytes, verb, goSyntax, depth, nil, value)
return verb == 's'
}
if goSyntax {
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(value.Type().String())
p.buf.WriteByte('{')
} else {
p.buf.WriteByte('[')
@@ -782,7 +839,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('}')
@@ -797,17 +854,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 {
@@ -824,7 +881,7 @@ BigSwitch:
}
p.fmt0x64(uint64(v), true)
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
- p.fmtPointer(field, value, verb, goSyntax)
+ p.fmtPointer(nil, value, verb, goSyntax)
default:
p.unknownType(f)
}