| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Reflection library. |
| // Formatting of reflection types and values for debugging. |
| // Not defined as methods so they do not need to be linked into most binaries; |
| // the functions are not used by the library itself, only in tests. |
| |
| package reflect |
| |
| import ( |
| "reflect"; |
| "strconv"; |
| ) |
| |
| func typeToString(typ Type, expand bool) string |
| func valueToString(val Value) string |
| |
| func doubleQuote(s string) string { |
| out := "\""; |
| for i := 0; i < len(s); i++ { |
| c := s[i]; |
| switch c { |
| case '\n': |
| out += `\n`; |
| case '\t': |
| out += `\t`; |
| case '\x00': |
| out += `\x00`; |
| case '"': |
| out += `\"`; |
| case '\\': |
| out += `\\`; |
| default: |
| out += string(c); |
| } |
| } |
| out += "\""; |
| return out; |
| } |
| |
| type hasFields interface { |
| Field(i int) (name string, typ Type, tag string, offset int); |
| Len() int; |
| } |
| |
| func typeFieldsToString(t hasFields, sep string, iface bool) string { |
| var str string; |
| for i := 0; i < t.Len(); i++ { |
| str1, typ, tag, offset := t.Field(i); |
| if str1 != "" { |
| str1 += " " |
| } |
| str2 := typeToString(typ, false); |
| if iface && str2[0:4] == "func" { |
| str2 = str2[4:len(str2)] |
| } |
| str1 += str2; |
| if tag != "" { |
| str1 += " " + doubleQuote(tag); |
| } |
| if i < t.Len() - 1 { |
| str1 += sep + " "; |
| } |
| str += str1; |
| } |
| return str; |
| } |
| |
| // typeToString returns a textual representation of typ. The expand |
| // flag specifies whether to expand the contents of type names; if false, |
| // the name itself is used as the representation. |
| // Meant for debugging only; typ.String() serves for most purposes. |
| func typeToString(typ Type, expand bool) string { |
| var str string; |
| if name := typ.Name(); !expand && name != "" { |
| return name |
| } |
| switch(typ.Kind()) { |
| case MissingKind: |
| return "$missing$"; |
| case IntKind, Int8Kind, Int16Kind, Int32Kind, Int64Kind, |
| UintKind, Uint8Kind, Uint16Kind, Uint32Kind, Uint64Kind, |
| FloatKind, Float32Kind, Float64Kind, |
| StringKind, |
| DotDotDotKind: |
| return typ.Name(); |
| case PtrKind: |
| p := typ.(PtrType); |
| return "*" + typeToString(p.Sub(), false); |
| case ArrayKind: |
| a := typ.(ArrayType); |
| if a.IsSlice() { |
| str = "[]" |
| } else { |
| str = "[" + strconv.Itoa64(int64(a.Len())) + "]" |
| } |
| return str + typeToString(a.Elem(), false); |
| case MapKind: |
| m := typ.(MapType); |
| str = "map[" + typeToString(m.Key(), false) + "]"; |
| return str + typeToString(m.Elem(), false); |
| case ChanKind: |
| c := typ.(ChanType); |
| switch c.Dir() { |
| case RecvDir: |
| str = "<-chan"; |
| case SendDir: |
| str = "chan<-"; |
| case BothDir: |
| str = "chan"; |
| default: |
| panicln("reflect.typeToString: unknown chan direction"); |
| } |
| return str + typeToString(c.Elem(), false); |
| case StructKind: |
| return "struct{" + typeFieldsToString(typ.(StructType), ";", false) + "}"; |
| case InterfaceKind: |
| return "interface{" + typeFieldsToString(typ.(InterfaceType), ";", true) + "}"; |
| case FuncKind: |
| f := typ.(FuncType); |
| str = "func(" + typeFieldsToString(f.In(), ",", false) + ")"; |
| if f.Out() != nil { |
| str += "(" + typeFieldsToString(f.Out(), ",", false) + ")"; |
| } |
| return str; |
| default: |
| panicln("reflect.typeToString: can't print type ", typ.Kind()); |
| } |
| return "reflect.typeToString: can't happen"; |
| } |
| |
| // TODO: want an unsigned one too |
| func integer(v int64) string { |
| return strconv.Itoa64(v); |
| } |
| |
| // valueToString returns a textual representation of the reflection value val. |
| // For debugging only. |
| func valueToString(val Value) string { |
| var str string; |
| typ := val.Type(); |
| switch(val.Kind()) { |
| case MissingKind: |
| return "missing"; |
| case IntKind: |
| return integer(int64(val.(IntValue).Get())); |
| case Int8Kind: |
| return integer(int64(val.(Int8Value).Get())); |
| case Int16Kind: |
| return integer(int64(val.(Int16Value).Get())); |
| case Int32Kind: |
| return integer(int64(val.(Int32Value).Get())); |
| case Int64Kind: |
| return integer(int64(val.(Int64Value).Get())); |
| case UintKind: |
| return integer(int64(val.(UintValue).Get())); |
| case Uint8Kind: |
| return integer(int64(val.(Uint8Value).Get())); |
| case Uint16Kind: |
| return integer(int64(val.(Uint16Value).Get())); |
| case Uint32Kind: |
| return integer(int64(val.(Uint32Value).Get())); |
| case Uint64Kind: |
| return integer(int64(val.(Uint64Value).Get())); |
| case FloatKind: |
| if strconv.FloatSize == 32 { |
| return strconv.Ftoa32(float32(val.(FloatValue).Get()), 'g', -1); |
| } else { |
| return strconv.Ftoa64(float64(val.(FloatValue).Get()), 'g', -1); |
| } |
| case Float32Kind: |
| return strconv.Ftoa32(val.(Float32Value).Get(), 'g', -1); |
| case Float64Kind: |
| return strconv.Ftoa64(val.(Float64Value).Get(), 'g', -1); |
| case StringKind: |
| return val.(StringValue).Get(); |
| case BoolKind: |
| if val.(BoolValue).Get() { |
| return "true" |
| } else { |
| return "false" |
| } |
| case PtrKind: |
| v := val.(PtrValue); |
| return typeToString(typ, false) + "(" + integer(int64(uintptr(v.Get()))) + ")"; |
| case ArrayKind: |
| t := typ.(ArrayType); |
| v := val.(ArrayValue); |
| str += typeToString(t, false); |
| str += "{"; |
| for i := 0; i < v.Len(); i++ { |
| if i > 0 { |
| str += ", " |
| } |
| str += valueToString(v.Elem(i)); |
| } |
| str += "}"; |
| return str; |
| case MapKind: |
| t := typ.(MapType); |
| v := val.(MapValue); |
| str = typeToString(t, false); |
| str += "{"; |
| str += "<can't iterate on maps>"; |
| str += "}"; |
| return str; |
| case ChanKind: |
| str = typeToString(typ, false); |
| return str; |
| case StructKind: |
| t := typ.(StructType); |
| v := val.(StructValue); |
| str += typeToString(t, false); |
| str += "{"; |
| for i := 0; i < v.Len(); i++ { |
| if i > 0 { |
| str += ", " |
| } |
| str += valueToString(v.Field(i)); |
| } |
| str += "}"; |
| return str; |
| case InterfaceKind: |
| return "can't print interfaces yet"; |
| case FuncKind: |
| v := val.(FuncValue); |
| return typeToString(typ, false) + "(" + integer(int64(uintptr(v.Get()))) + ")"; |
| default: |
| panicln("reflect.valueToString: can't print type ", val.Kind()); |
| } |
| return "reflect.valueToString: can't happen"; |
| } |