2020-10-22 20:55:32 +02:00
|
|
|
package notation
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"reflect"
|
|
|
|
"sort"
|
2020-11-23 15:42:05 +01:00
|
|
|
"strconv"
|
2020-11-22 19:14:45 +01:00
|
|
|
"strings"
|
2020-10-22 20:55:32 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
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 reflectPrimitive(o opts, r reflect.Value, v interface{}, suppressType ...string) node {
|
|
|
|
s := fmt.Sprint(v)
|
|
|
|
if s[0] == '(' && s[len(s)-1] == ')' {
|
|
|
|
s = s[1 : len(s)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
_, t, a := withType(o)
|
|
|
|
if !t {
|
|
|
|
return nodeOf(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
tn := reflectType(r.Type())
|
|
|
|
if a {
|
|
|
|
return nodeOf(tn, "(", s, ")")
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, suppress := range suppressType {
|
2020-11-26 14:27:42 +01:00
|
|
|
if tn.parts[0] == suppress {
|
|
|
|
return nodeOf(s)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodeOf(tn, "(", s, ")")
|
|
|
|
}
|
|
|
|
|
2020-11-10 00:56:25 +01:00
|
|
|
func reflectNil(o opts, groupUnnamedType bool, r reflect.Value) node {
|
2020-10-22 20:55:32 +02:00
|
|
|
if _, _, a := withType(o); !a {
|
|
|
|
return nodeOf("nil")
|
|
|
|
}
|
|
|
|
|
2020-11-10 00:56:25 +01:00
|
|
|
rt := r.Type()
|
|
|
|
if groupUnnamedType && rt.Name() == "" {
|
|
|
|
return nodeOf("(", reflectType(rt), ")(nil)")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodeOf(reflectType(rt), "(nil)")
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
func reflectItems(o opts, p *pending, prefix string, r reflect.Value) node {
|
2020-11-10 00:56:25 +01:00
|
|
|
typ := r.Type()
|
2020-11-26 14:27:42 +01:00
|
|
|
var w wrapper
|
|
|
|
if typ.Elem().Kind() == reflect.Uint8 {
|
|
|
|
w.sep = " "
|
|
|
|
w.mode = line
|
2020-11-10 00:56:25 +01:00
|
|
|
for i := 0; i < r.Len(); i++ {
|
2020-11-26 14:27:42 +01:00
|
|
|
w.items = append(
|
|
|
|
w.items,
|
2020-11-10 00:56:25 +01:00
|
|
|
nodeOf(fmt.Sprintf("%02x", r.Index(i).Uint())),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
} else {
|
2020-11-26 14:27:42 +01:00
|
|
|
w.sep = ", "
|
|
|
|
w.suffix = ","
|
2020-11-10 00:56:25 +01:00
|
|
|
itemOpts := o | skipTypes
|
|
|
|
for i := 0; i < r.Len(); i++ {
|
2020-11-26 14:27:42 +01:00
|
|
|
w.items = append(
|
|
|
|
w.items,
|
2020-11-22 23:22:20 +01:00
|
|
|
reflectValue(itemOpts, p, r.Index(i)),
|
2020-11-10 00:56:25 +01:00
|
|
|
)
|
|
|
|
}
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
if _, t, _ := withType(o); t {
|
|
|
|
return nodeOf(reflectType(typ), "{", w, "}")
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
return nodeOf(prefix, "{", w, "}")
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func reflectHidden(o opts, hidden string, r reflect.Value) node {
|
|
|
|
if r.IsNil() {
|
2020-11-10 00:56:25 +01:00
|
|
|
return reflectNil(o, true, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
if _, t, _ := withType(o); t {
|
|
|
|
return reflectType(r.Type())
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
return nodeOf(hidden)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
func reflectArray(o opts, p *pending, r reflect.Value) node {
|
|
|
|
return reflectItems(o, p, fmt.Sprintf("[%d]", r.Len()), r)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func reflectChan(o opts, r reflect.Value) node {
|
|
|
|
return reflectHidden(o, "chan", r)
|
|
|
|
}
|
|
|
|
|
|
|
|
func reflectFunc(o opts, r reflect.Value) node {
|
|
|
|
return reflectHidden(o, "func()", r)
|
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
func reflectInterface(o opts, p *pending, r reflect.Value) node {
|
2020-10-22 20:55:32 +02:00
|
|
|
if r.IsNil() {
|
2020-11-10 00:56:25 +01:00
|
|
|
return reflectNil(o, false, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-23 00:46:14 +01:00
|
|
|
e := reflectValue(o&^skipTypes, p, r.Elem())
|
2020-10-22 20:55:32 +02:00
|
|
|
if _, t, _ := withType(o); !t {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodeOf(
|
|
|
|
reflectType(r.Type()),
|
|
|
|
"(",
|
|
|
|
wrapper{items: []node{e}},
|
|
|
|
")",
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
func reflectMap(o opts, p *pending, r reflect.Value) node {
|
2020-10-22 20:55:32 +02:00
|
|
|
if r.IsNil() {
|
2020-11-10 00:56:25 +01:00
|
|
|
return reflectNil(o, true, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-23 15:42:05 +01:00
|
|
|
var skeys []string
|
2020-10-22 20:55:32 +02:00
|
|
|
itemOpts := o | skipTypes
|
|
|
|
sv := make(map[string]reflect.Value)
|
|
|
|
sn := make(map[string]node)
|
2020-11-26 14:27:42 +01:00
|
|
|
for _, key := range r.MapKeys() {
|
|
|
|
kn := reflectValue(itemOpts, p, key)
|
2020-12-06 22:30:19 +01:00
|
|
|
knExt := reflectValue(allTypes|pointerValues, p, key)
|
2020-10-22 20:55:32 +02:00
|
|
|
var b bytes.Buffer
|
|
|
|
wr := writer{w: &b}
|
2020-12-06 22:30:19 +01:00
|
|
|
fprint(&wr, 0, knExt)
|
2020-10-22 20:55:32 +02:00
|
|
|
skey := b.String()
|
|
|
|
skeys = append(skeys, skey)
|
|
|
|
sv[skey] = key
|
2020-11-26 14:27:42 +01:00
|
|
|
sn[skey] = kn
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-10 00:56:25 +01:00
|
|
|
if o&randomMaps == 0 {
|
|
|
|
sort.Strings(skeys)
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
w := wrapper{sep: ", ", suffix: ","}
|
2020-10-22 20:55:32 +02:00
|
|
|
for _, skey := range skeys {
|
2020-11-26 14:27:42 +01:00
|
|
|
vn := reflectValue(itemOpts, p, r.MapIndex(sv[skey]))
|
|
|
|
w.items = append(
|
|
|
|
w.items,
|
|
|
|
nodeOf(sn[skey], ": ", vn),
|
2020-10-22 20:55:32 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, t, _ := withType(o); !t {
|
2020-11-26 14:27:42 +01:00
|
|
|
return nodeOf("map{", w, "}")
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
return nodeOf(reflectType(r.Type()), "{", w, "}")
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
func reflectPointer(o opts, p *pending, r reflect.Value) node {
|
2020-10-22 20:55:32 +02:00
|
|
|
if r.IsNil() {
|
2020-11-10 00:56:25 +01:00
|
|
|
return reflectNil(o, true, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
e := reflectValue(o, p, r.Elem())
|
2020-10-22 20:55:32 +02:00
|
|
|
if _, t, _ := withType(o); !t {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
2020-12-06 22:30:19 +01:00
|
|
|
if o&pointerValues == 0 {
|
|
|
|
return nodeOf("*", e)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodeOf("*(", r.Pointer(), ")", e)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
func reflectList(o opts, p *pending, r reflect.Value) node {
|
2020-10-22 20:55:32 +02:00
|
|
|
if r.IsNil() {
|
2020-11-10 00:56:25 +01:00
|
|
|
return reflectNil(o, true, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
return reflectItems(o, p, "[]", r)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func reflectString(o opts, r reflect.Value) node {
|
2020-11-22 19:14:45 +01:00
|
|
|
sv := r.String()
|
2020-11-23 15:42:05 +01:00
|
|
|
s := str{val: strconv.Quote(sv)}
|
2020-11-22 19:14:45 +01:00
|
|
|
if !strings.Contains(sv, "`") && strings.Contains(sv, "\n") {
|
|
|
|
s.raw = fmt.Sprintf("`%s`", sv)
|
|
|
|
}
|
|
|
|
|
|
|
|
n := nodeOf(s)
|
2020-10-22 20:55:32 +02:00
|
|
|
_, t, a := withType(o)
|
|
|
|
if !t {
|
2020-11-22 19:14:45 +01:00
|
|
|
return n
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
tn := reflectType(r.Type())
|
|
|
|
if !a && tn.parts[0] == "string" {
|
2020-11-22 19:14:45 +01:00
|
|
|
return n
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 19:14:45 +01:00
|
|
|
return nodeOf(tn, "(", wrapper{items: []node{n}}, ")")
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
func reflectStruct(o opts, p *pending, r reflect.Value) node {
|
2020-11-10 00:56:25 +01:00
|
|
|
wr := wrapper{sep: ", ", suffix: ","}
|
2020-10-22 20:55:32 +02:00
|
|
|
|
|
|
|
fieldOpts := o | skipTypes
|
|
|
|
rt := r.Type()
|
|
|
|
for i := 0; i < r.NumField(); i++ {
|
|
|
|
name := rt.Field(i).Name
|
2020-11-26 14:27:42 +01:00
|
|
|
fv := reflectValue(fieldOpts, p, r.FieldByName(name))
|
2020-10-22 20:55:32 +02:00
|
|
|
wr.items = append(
|
|
|
|
wr.items,
|
2020-11-26 14:27:42 +01:00
|
|
|
nodeOf(name, ": ", fv),
|
2020-10-22 20:55:32 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, t, _ := withType(o); !t {
|
|
|
|
return nodeOf("{", wr, "}")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodeOf(reflectType(rt), "{", wr, "}")
|
|
|
|
}
|
|
|
|
|
|
|
|
func reflectUnsafePointer(o opts, r reflect.Value) node {
|
|
|
|
if r.IsNil() {
|
2020-11-10 00:56:25 +01:00
|
|
|
return reflectNil(o, false, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if _, _, a := withType(o); !a {
|
|
|
|
return nodeOf("pointer")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodeOf(reflectType(r.Type()), "(pointer)")
|
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
func checkPending(p *pending, r reflect.Value) (applyRef func(node) node, ref node, isPending bool) {
|
|
|
|
applyRef = func(n node) node { return n }
|
|
|
|
switch r.Kind() {
|
2020-11-26 14:27:42 +01:00
|
|
|
case reflect.Slice, reflect.Map, reflect.Ptr:
|
2020-11-22 23:22:20 +01:00
|
|
|
default:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-26 14:27:42 +01:00
|
|
|
if r.IsNil() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-22 23:22:20 +01:00
|
|
|
var nr nodeRef
|
2020-11-23 00:46:14 +01:00
|
|
|
key := r.Pointer()
|
2020-11-22 23:22:20 +01:00
|
|
|
nr, isPending = p.values[key]
|
|
|
|
if isPending {
|
|
|
|
nr.refCount++
|
|
|
|
p.values[key] = nr
|
|
|
|
ref = nodeOf("r", nr.id)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
nr = nodeRef{id: p.idCounter}
|
|
|
|
p.idCounter++
|
|
|
|
p.values[key] = nr
|
|
|
|
applyRef = func(n node) node {
|
|
|
|
nr = p.values[key]
|
|
|
|
if nr.refCount > 0 {
|
2020-12-06 22:36:09 +01:00
|
|
|
def := []interface{}{"r", nr.id, "="}
|
|
|
|
pp := make([]interface{}, len(def)+len(n.parts))
|
|
|
|
copy(pp, def)
|
|
|
|
copy(pp[len(def):], n.parts)
|
|
|
|
n.parts = pp
|
2020-11-22 23:22:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
delete(p.values, key)
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func reflectValue(o opts, p *pending, r reflect.Value) node {
|
|
|
|
applyRef, ref, isPending := checkPending(p, r)
|
|
|
|
if isPending {
|
|
|
|
return ref
|
|
|
|
}
|
|
|
|
|
|
|
|
var n node
|
2020-10-22 20:55:32 +02:00
|
|
|
switch r.Kind() {
|
|
|
|
case reflect.Bool:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectPrimitive(o, r, r.Bool(), "bool")
|
2020-10-22 20:55:32 +02:00
|
|
|
case
|
|
|
|
reflect.Int,
|
|
|
|
reflect.Int8,
|
|
|
|
reflect.Int16,
|
|
|
|
reflect.Int32,
|
|
|
|
reflect.Int64:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectPrimitive(o, r, r.Int(), "int")
|
2020-10-22 20:55:32 +02:00
|
|
|
case
|
|
|
|
reflect.Uint,
|
|
|
|
reflect.Uint8,
|
|
|
|
reflect.Uint16,
|
|
|
|
reflect.Uint32,
|
|
|
|
reflect.Uint64,
|
|
|
|
reflect.Uintptr:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectPrimitive(o, r, r.Uint())
|
2020-10-22 20:55:32 +02:00
|
|
|
case reflect.Float32, reflect.Float64:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectPrimitive(o, r, r.Float())
|
2020-10-22 20:55:32 +02:00
|
|
|
case reflect.Complex64, reflect.Complex128:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectPrimitive(o, r, r.Complex())
|
2020-10-22 20:55:32 +02:00
|
|
|
case reflect.Array:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectArray(o, p, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
case reflect.Chan:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectChan(o, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
case reflect.Func:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectFunc(o, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
case reflect.Interface:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectInterface(o, p, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
case reflect.Map:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectMap(o, p, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
case reflect.Ptr:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectPointer(o, p, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
case reflect.Slice:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectList(o, p, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
case reflect.String:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectString(o, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
case reflect.UnsafePointer:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectUnsafePointer(o, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
default:
|
2020-11-22 23:22:20 +01:00
|
|
|
n = reflectStruct(o, p, r)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|
2020-11-22 23:22:20 +01:00
|
|
|
|
|
|
|
return applyRef(n)
|
2020-10-22 20:55:32 +02:00
|
|
|
}
|