github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/eval/vals/repr.go (about) 1 package vals 2 3 import ( 4 "fmt" 5 "math" 6 "math/big" 7 "reflect" 8 "strconv" 9 10 "src.elv.sh/pkg/parse" 11 ) 12 13 // NoPretty can be passed to Repr to suppress pretty-printing. 14 const NoPretty = math.MinInt32 15 16 // Reprer wraps the Repr method. 17 type Reprer interface { 18 // Repr returns a string that represents a Value. The string either be a 19 // literal of that Value that is preferably deep-equal to it (like `[a b c]` 20 // for a list), or a string enclosed in "<>" containing the kind and 21 // identity of the Value(like `<fn 0xdeadcafe>`). 22 // 23 // If indent is at least 0, it should be pretty-printed with the current 24 // indentation level of indent; the indent of the first line has already 25 // been written and shall not be written in Repr. The returned string 26 // should never contain a trailing newline. 27 Repr(indent int) string 28 } 29 30 // Repr returns the representation for a value, a string that is preferably (but 31 // not necessarily) an Elvish expression that evaluates to the argument. If 32 // indent >= 0, the representation is pretty-printed. It is implemented for the 33 // builtin types nil, bool and string, the File, List and Map types, StructMap 34 // types, and types satisfying the Reprer interface. For other types, it uses 35 // fmt.Sprint with the format "<unknown %v>". 36 func Repr(v interface{}, indent int) string { 37 switch v := v.(type) { 38 case nil: 39 return "$nil" 40 case bool: 41 if v { 42 return "$true" 43 } 44 return "$false" 45 case string: 46 return parse.Quote(v) 47 case int: 48 return "(num " + strconv.Itoa(v) + ")" 49 case *big.Int: 50 return "(num " + v.String() + ")" 51 case *big.Rat: 52 return "(num " + v.String() + ")" 53 case float64: 54 return "(num " + formatFloat64(v) + ")" 55 case Reprer: 56 return v.Repr(indent) 57 case File: 58 return fmt.Sprintf("<file{%s %d}>", parse.Quote(v.Name()), v.Fd()) 59 case List: 60 b := NewListReprBuilder(indent) 61 for it := v.Iterator(); it.HasElem(); it.Next() { 62 b.WriteElem(Repr(it.Elem(), indent+1)) 63 } 64 return b.String() 65 case Map: 66 builder := NewMapReprBuilder(indent) 67 for it := v.Iterator(); it.HasElem(); it.Next() { 68 k, v := it.Elem() 69 builder.WritePair(Repr(k, indent+1), indent+2, Repr(v, indent+2)) 70 } 71 return builder.String() 72 case StructMap: 73 return reprStructMap(v, indent) 74 case PseudoStructMap: 75 return reprStructMap(v.Fields(), indent) 76 default: 77 return fmt.Sprintf("<unknown %v>", v) 78 } 79 } 80 81 func reprStructMap(v StructMap, indent int) string { 82 vValue := reflect.ValueOf(v) 83 vType := vValue.Type() 84 builder := NewMapReprBuilder(indent) 85 it := iterateStructMap(vType) 86 for it.Next() { 87 k, v := it.Get(vValue) 88 builder.WritePair(Repr(k, indent+1), indent+2, Repr(v, indent+2)) 89 } 90 return builder.String() 91 }