272 lines
5.1 KiB
Go
272 lines
5.1 KiB
Go
package notation
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
func withType(o opts) (opts, bool, bool) {
|
|
if o&types == 0 && o&allTypes == 0 {
|
|
return o, false, false
|
|
}
|
|
|
|
if o&skipTypes != 0 && o&allTypes == 0 {
|
|
return o &^ skipTypes, false, false
|
|
}
|
|
|
|
return o, true, o&allTypes != 0
|
|
}
|
|
|
|
func sprintNil(o opts, r reflect.Value) string {
|
|
if _, _, a := withType(o); !a {
|
|
return "nil"
|
|
}
|
|
|
|
return fmt.Sprintf("%s(nil)", sprintType(r.Type()))
|
|
}
|
|
|
|
func sprintPrimitive(o opts, r reflect.Value, v interface{}, suppressType ...string) string {
|
|
s := fmt.Sprint(v)
|
|
if s[0] == '(' && s[len(s)-1] == ')' {
|
|
s = s[1 : len(s)-1]
|
|
}
|
|
|
|
_, w, a := withType(o)
|
|
if !w {
|
|
return s
|
|
}
|
|
|
|
t := sprintType(r.Type())
|
|
if !a {
|
|
for _, suppress := range suppressType {
|
|
if t == suppress {
|
|
return s
|
|
}
|
|
}
|
|
}
|
|
|
|
return fmt.Sprintf("%s(%s)", t, s)
|
|
}
|
|
|
|
func sprintItems(o opts, prefix string, r reflect.Value) string {
|
|
o, w, _ := withType(o)
|
|
itemOpts := o | skipTypes
|
|
s := make([]string, r.Len())
|
|
for i := 0; i < r.Len(); i++ {
|
|
s[i] = sprint(itemOpts, r.Index(i))
|
|
}
|
|
|
|
if !w {
|
|
return fmt.Sprintf("%s{%s}", prefix, strings.Join(s, ", "))
|
|
}
|
|
|
|
return fmt.Sprintf("%s{%s}", sprintType(r.Type()), strings.Join(s, ", "))
|
|
}
|
|
|
|
func sprintHidden(o opts, r reflect.Value, hidden string) string {
|
|
if r.IsNil() {
|
|
return sprintNil(o, r)
|
|
}
|
|
|
|
_, w, _ := withType(o)
|
|
if !w {
|
|
return hidden
|
|
}
|
|
|
|
return sprintType(r.Type())
|
|
}
|
|
|
|
func sprintArray(o opts, r reflect.Value) string {
|
|
return sprintItems(o, fmt.Sprintf("[%d]", r.Len()), r)
|
|
}
|
|
|
|
func sprintChan(o opts, r reflect.Value) string {
|
|
return sprintHidden(o, r, "chan")
|
|
}
|
|
|
|
func sprintFunc(o opts, r reflect.Value) string {
|
|
return sprintHidden(o, r, "func()")
|
|
}
|
|
|
|
func sprinterface(o opts, r reflect.Value) string {
|
|
if r.IsNil() {
|
|
return sprintNil(o, r)
|
|
}
|
|
|
|
o, w, _ := withType(o)
|
|
if !w {
|
|
return sprint(o, r.Elem())
|
|
}
|
|
|
|
return fmt.Sprintf("%s(%s)", sprintType(r.Type()), sprint(o, r.Elem()))
|
|
}
|
|
|
|
func sprintMap(o opts, r reflect.Value) string {
|
|
if r.IsNil() {
|
|
return sprintNil(o, r)
|
|
}
|
|
|
|
o, w, _ := withType(o)
|
|
itemOpts := o | skipTypes
|
|
var items []string
|
|
for _, key := range r.MapKeys() {
|
|
items = append(
|
|
items,
|
|
fmt.Sprintf(
|
|
"%s: %s",
|
|
sprint(itemOpts, key),
|
|
sprint(itemOpts, r.MapIndex(key)),
|
|
),
|
|
)
|
|
}
|
|
|
|
sort.Strings(items)
|
|
sitems := strings.Join(items, ", ")
|
|
if !w {
|
|
return fmt.Sprintf("map{%s}", sitems)
|
|
}
|
|
|
|
return fmt.Sprintf("%s{%s}", sprintType(r.Type()), sitems)
|
|
}
|
|
|
|
func sprintPointer(o opts, r reflect.Value) string {
|
|
if r.IsNil() {
|
|
return sprintNil(o, r)
|
|
}
|
|
|
|
s := sprint(o, r.Elem())
|
|
if _, w, _ := withType(o); !w {
|
|
return s
|
|
}
|
|
|
|
return fmt.Sprintf("*%s", s)
|
|
}
|
|
|
|
func sprintList(o opts, r reflect.Value) string {
|
|
if r.IsNil() {
|
|
return sprintNil(o, r)
|
|
}
|
|
|
|
return sprintItems(o, "[]", r)
|
|
}
|
|
|
|
func sprintString(o opts, r reflect.Value) string {
|
|
b := []byte(r.String())
|
|
e := make([]byte, 0, len(b))
|
|
for _, c := range b {
|
|
switch c {
|
|
case '\\':
|
|
e = append(e, '\\', '\\')
|
|
case '"':
|
|
e = append(e, '\\', '"')
|
|
case '\b':
|
|
e = append(e, '\\', 'b')
|
|
case '\f':
|
|
e = append(e, '\\', 'f')
|
|
case '\n':
|
|
e = append(e, '\\', 'n')
|
|
case '\r':
|
|
e = append(e, '\\', 'r')
|
|
case '\t':
|
|
e = append(e, '\\', 't')
|
|
case '\v':
|
|
e = append(e, '\\', 'v')
|
|
default:
|
|
e = append(e, c)
|
|
}
|
|
}
|
|
|
|
s := fmt.Sprintf("\"%s\"", string(e))
|
|
_, w, a := withType(o)
|
|
if !w {
|
|
return s
|
|
}
|
|
|
|
t := sprintType(r.Type())
|
|
if !a && t == "string" {
|
|
return s
|
|
}
|
|
|
|
return fmt.Sprintf("%s(%s)", t, s)
|
|
}
|
|
|
|
func sprintStruct(o opts, r reflect.Value) string {
|
|
o, w, _ := withType(o)
|
|
fieldOpts := o | skipTypes
|
|
rt := r.Type()
|
|
f := make([]string, r.NumField())
|
|
for i := 0; i < r.NumField(); i++ {
|
|
name := rt.Field(i).Name
|
|
f[i] = fmt.Sprintf(
|
|
"%s: %s",
|
|
name,
|
|
sprint(fieldOpts, r.FieldByName(name)),
|
|
)
|
|
}
|
|
|
|
fs := strings.Join(f, ", ")
|
|
if !w {
|
|
return fmt.Sprintf("{%s}", fs)
|
|
}
|
|
|
|
return fmt.Sprintf("%s{%s}", sprintType(rt), fs)
|
|
}
|
|
|
|
func sprintUnsafePointer(o opts, r reflect.Value) string {
|
|
if r.IsNil() {
|
|
return sprintNil(o, r)
|
|
}
|
|
|
|
return "pointer"
|
|
}
|
|
|
|
func sprint(o opts, r reflect.Value) string {
|
|
switch r.Kind() {
|
|
case reflect.Bool:
|
|
return sprintPrimitive(o, r, r.Bool(), "bool")
|
|
case
|
|
reflect.Int,
|
|
reflect.Int8,
|
|
reflect.Int16,
|
|
reflect.Int32,
|
|
reflect.Int64:
|
|
return sprintPrimitive(o, r, r.Int(), "int")
|
|
case
|
|
reflect.Uint,
|
|
reflect.Uint8,
|
|
reflect.Uint16,
|
|
reflect.Uint32,
|
|
reflect.Uint64,
|
|
reflect.Uintptr:
|
|
return sprintPrimitive(o, r, r.Uint())
|
|
case reflect.Float32, reflect.Float64:
|
|
return sprintPrimitive(o, r, r.Float())
|
|
case reflect.Complex64, reflect.Complex128:
|
|
return sprintPrimitive(o, r, r.Complex())
|
|
case reflect.Array:
|
|
return sprintArray(o, r)
|
|
case reflect.Chan:
|
|
return sprintChan(o, r)
|
|
case reflect.Func:
|
|
return sprintFunc(o, r)
|
|
case reflect.Interface:
|
|
return sprinterface(o, r)
|
|
case reflect.Map:
|
|
return sprintMap(o, r)
|
|
case reflect.Ptr:
|
|
return sprintPointer(o, r)
|
|
case reflect.Slice:
|
|
return sprintList(o, r)
|
|
case reflect.String:
|
|
return sprintString(o, r)
|
|
case reflect.Struct:
|
|
return sprintStruct(o, r)
|
|
case reflect.UnsafePointer:
|
|
return sprintUnsafePointer(o, r)
|
|
default:
|
|
return "<invalid>"
|
|
}
|
|
}
|