wrap lines
This commit is contained in:
parent
79047a09dd
commit
612aa94f0a
168
fprint.go
Normal file
168
fprint.go
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
package notation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type writer struct {
|
||||||
|
w io.Writer
|
||||||
|
n int
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writer) write(o interface{}) {
|
||||||
|
if w.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := fmt.Fprint(w.w, o)
|
||||||
|
w.n += n
|
||||||
|
w.err = err
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeLen(t int, n node) node {
|
||||||
|
var w int
|
||||||
|
for i, p := range n.parts {
|
||||||
|
switch part := p.(type) {
|
||||||
|
case string:
|
||||||
|
n.len += len(part)
|
||||||
|
w += len(part)
|
||||||
|
case node:
|
||||||
|
part = nodeLen(t, part)
|
||||||
|
n.parts[i] = part
|
||||||
|
n.len += part.len
|
||||||
|
if part.len == part.wlen {
|
||||||
|
w += part.len
|
||||||
|
} else {
|
||||||
|
w += part.wlen0
|
||||||
|
if w > n.wlen {
|
||||||
|
n.wlen = w
|
||||||
|
}
|
||||||
|
|
||||||
|
if part.wlen > n.wlen {
|
||||||
|
n.wlen = part.wlen
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.wlen0 == 0 {
|
||||||
|
n.wlen0 = w
|
||||||
|
}
|
||||||
|
|
||||||
|
w = part.wlenLast
|
||||||
|
}
|
||||||
|
case wrapper:
|
||||||
|
if len(part.items) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if w > n.wlen {
|
||||||
|
n.wlen = w
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.wlen0 == 0 {
|
||||||
|
n.wlen0 = w
|
||||||
|
}
|
||||||
|
|
||||||
|
w = 0
|
||||||
|
for j, ni := range part.items {
|
||||||
|
ni = nodeLen(t, ni)
|
||||||
|
part.items[j] = ni
|
||||||
|
n.len += ni.len
|
||||||
|
wni := t + ni.len + len(part.suffix)
|
||||||
|
if wni > w {
|
||||||
|
w = wni
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(part.items) > 0 {
|
||||||
|
n.len += (len(part.items) - 1) * len(part.sep)
|
||||||
|
}
|
||||||
|
|
||||||
|
w = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if w > n.wlen {
|
||||||
|
n.wlen = w
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.wlen0 == 0 {
|
||||||
|
n.wlen0 = w
|
||||||
|
}
|
||||||
|
|
||||||
|
n.wlenLast = w
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapNode(t, c0, c1 int, n node) node {
|
||||||
|
if n.len <= c0 || n.wlen == n.len {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.len <= c1 && n.len-c0 <= n.wlen {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
n.wrap = true
|
||||||
|
if n.wlen <= c0 {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, p := range n.parts {
|
||||||
|
switch part := p.(type) {
|
||||||
|
case node:
|
||||||
|
n.parts[i] = wrapNode(t, c0, c1, part)
|
||||||
|
case wrapper:
|
||||||
|
for j := range part.items {
|
||||||
|
part.items[j] = wrapNode(
|
||||||
|
t,
|
||||||
|
c0-t,
|
||||||
|
c1-t,
|
||||||
|
part.items[j],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func fprint(w *writer, t int, n node) {
|
||||||
|
if w.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < t; i++ {
|
||||||
|
w.write("\t")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range n.parts {
|
||||||
|
switch part := p.(type) {
|
||||||
|
case node:
|
||||||
|
fprint(w, 0, part)
|
||||||
|
case wrapper:
|
||||||
|
if len(part.items) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.wrap {
|
||||||
|
w.write("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, ni := range part.items {
|
||||||
|
if n.wrap {
|
||||||
|
fprint(w, t+1, ni)
|
||||||
|
w.write(part.suffix)
|
||||||
|
w.write("\n")
|
||||||
|
} else {
|
||||||
|
fprint(w, 0, ni)
|
||||||
|
if i < len(part.items)-1 {
|
||||||
|
w.write(part.sep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
w.write(part)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
105
notation.go
105
notation.go
@ -1,7 +1,11 @@
|
|||||||
package notation
|
package notation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,23 +20,102 @@ const (
|
|||||||
allTypes
|
allTypes
|
||||||
)
|
)
|
||||||
|
|
||||||
func sprintValues(o opts, v []interface{}) string {
|
type node struct {
|
||||||
s := make([]string, len(v))
|
len, wlen, wlen0, wlenLast int
|
||||||
for i := range v {
|
wrap bool
|
||||||
if v[i] == nil {
|
parts []interface{}
|
||||||
s[i] = "nil"
|
}
|
||||||
|
|
||||||
|
type wrapper struct {
|
||||||
|
sep, suffix string
|
||||||
|
items []node
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeOf(parts ...interface{}) node {
|
||||||
|
return node{parts: parts}
|
||||||
|
}
|
||||||
|
|
||||||
|
func config(name string, dflt int) int {
|
||||||
|
s := os.Getenv(name)
|
||||||
|
if s == "" {
|
||||||
|
s = os.Getenv(strings.ToLower(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
if s == "" {
|
||||||
|
return dflt
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := strconv.Atoi(s)
|
||||||
|
if err != nil {
|
||||||
|
return dflt
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func fprintValues(w io.Writer, o opts, v []interface{}) (int, error) {
|
||||||
|
tab := config("TABWIDTH", 8)
|
||||||
|
cols0 := config("LINEWIDTH", 80-8)
|
||||||
|
cols1 := config("LINEWIDTH1", (cols0+8)*3/2-8)
|
||||||
|
wr := &writer{w: w}
|
||||||
|
for i, vi := range v {
|
||||||
|
if wr.err != nil {
|
||||||
|
return wr.n, wr.err
|
||||||
|
}
|
||||||
|
|
||||||
|
if i > 0 {
|
||||||
|
if o&wrap == 0 {
|
||||||
|
wr.write(" ")
|
||||||
|
} else {
|
||||||
|
wr.write("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if vi == nil {
|
||||||
|
fprint(wr, 0, nodeOf("nil"))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
s[i] = sprint(o, reflect.ValueOf(v[i]))
|
n := reflectValue(o, reflect.ValueOf(vi))
|
||||||
}
|
|
||||||
|
|
||||||
sep := " "
|
|
||||||
if o&wrap != 0 {
|
if o&wrap != 0 {
|
||||||
sep = "\n"
|
n = nodeLen(tab, n)
|
||||||
|
n = wrapNode(tab, cols0, cols1, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(s, sep)
|
fprint(wr, 0, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return wr.n, wr.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func sprintValues(o opts, v []interface{}) string {
|
||||||
|
var b bytes.Buffer
|
||||||
|
fprintValues(&b, o, v)
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fprint(w io.Writer, v ...interface{}) (int, error) {
|
||||||
|
return fprintValues(w, none, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fprintw(w io.Writer, v ...interface{}) (int, error) {
|
||||||
|
return fprintValues(w, wrap, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fprintt(w io.Writer, v ...interface{}) (int, error) {
|
||||||
|
return fprintValues(w, types, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fprintwt(w io.Writer, v ...interface{}) (int, error) {
|
||||||
|
return fprintValues(w, wrap|types, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fprintv(w io.Writer, v ...interface{}) (int, error) {
|
||||||
|
return fprintValues(w, allTypes, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fprintwv(w io.Writer, v ...interface{}) (int, error) {
|
||||||
|
return fprintValues(w, wrap|allTypes, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Sprint(v ...interface{}) string {
|
func Sprint(v ...interface{}) string {
|
||||||
|
308
reflect.go
Normal file
308
reflect.go
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
package notation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 {
|
||||||
|
if tn.parts[0] != suppress {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf(tn, "(", s, ")")
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectNil(o opts, r reflect.Value) node {
|
||||||
|
if _, _, a := withType(o); !a {
|
||||||
|
return nodeOf("nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf(reflectType(r.Type()), "(nil)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectItems(o opts, prefix string, r reflect.Value) node {
|
||||||
|
items := wrapper{sep: ", ", suffix: ","}
|
||||||
|
itemOpts := o | skipTypes
|
||||||
|
for i := 0; i < r.Len(); i++ {
|
||||||
|
items.items = append(
|
||||||
|
items.items,
|
||||||
|
reflectValue(itemOpts, r.Index(i)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, t, _ := withType(o); !t {
|
||||||
|
return nodeOf(prefix, "{", items, "}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf(reflectType(r.Type()), "{", items, "}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectHidden(o opts, hidden string, r reflect.Value) node {
|
||||||
|
if r.IsNil() {
|
||||||
|
return reflectNil(o, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, t, _ := withType(o); !t {
|
||||||
|
return nodeOf(hidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflectType(r.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectArray(o opts, r reflect.Value) node {
|
||||||
|
return reflectItems(o, fmt.Sprintf("[%d]", r.Len()), r)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectInterface(o opts, r reflect.Value) node {
|
||||||
|
if r.IsNil() {
|
||||||
|
return reflectNil(o, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
e := reflectValue(o, r.Elem())
|
||||||
|
if _, t, _ := withType(o); !t {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf(
|
||||||
|
reflectType(r.Type()),
|
||||||
|
"(",
|
||||||
|
wrapper{items: []node{e}},
|
||||||
|
")",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectMap(o opts, r reflect.Value) node {
|
||||||
|
if r.IsNil() {
|
||||||
|
return reflectNil(o, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
nkeys []node
|
||||||
|
skeys []string
|
||||||
|
)
|
||||||
|
|
||||||
|
items := wrapper{sep: ", ", suffix: ","}
|
||||||
|
itemOpts := o | skipTypes
|
||||||
|
keys := r.MapKeys()
|
||||||
|
sv := make(map[string]reflect.Value)
|
||||||
|
sn := make(map[string]node)
|
||||||
|
for _, key := range keys {
|
||||||
|
var b bytes.Buffer
|
||||||
|
nk := reflectValue(itemOpts, key)
|
||||||
|
nkeys = append(nkeys, nk)
|
||||||
|
wr := writer{w: &b}
|
||||||
|
fprint(&wr, 0, nk)
|
||||||
|
skey := b.String()
|
||||||
|
skeys = append(skeys, skey)
|
||||||
|
sv[skey] = key
|
||||||
|
sn[skey] = nk
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(skeys)
|
||||||
|
for _, skey := range skeys {
|
||||||
|
items.items = append(
|
||||||
|
items.items,
|
||||||
|
nodeOf(
|
||||||
|
sn[skey],
|
||||||
|
": ",
|
||||||
|
reflectValue(itemOpts, r.MapIndex(sv[skey])),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, t, _ := withType(o); !t {
|
||||||
|
return nodeOf("map{", items, "}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf(reflectType(r.Type()), "{", items, "}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectPointer(o opts, r reflect.Value) node {
|
||||||
|
if r.IsNil() {
|
||||||
|
return reflectNil(o, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
e := reflectValue(o, r.Elem())
|
||||||
|
if _, t, _ := withType(o); !t {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf("*", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectList(o opts, r reflect.Value) node {
|
||||||
|
if r.IsNil() {
|
||||||
|
return reflectNil(o, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflectItems(o, "[]", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectString(o opts, r reflect.Value) node {
|
||||||
|
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))
|
||||||
|
_, t, a := withType(o)
|
||||||
|
if !t {
|
||||||
|
return nodeOf(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
tn := reflectType(r.Type())
|
||||||
|
if !a && tn.parts[0] == "string" {
|
||||||
|
return nodeOf(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf(tn, "(", wrapper{items: []node{nodeOf(s)}}, ")")
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectStruct(o opts, r reflect.Value) node {
|
||||||
|
wr := wrapper{sep: ", "}
|
||||||
|
|
||||||
|
fieldOpts := o | skipTypes
|
||||||
|
rt := r.Type()
|
||||||
|
for i := 0; i < r.NumField(); i++ {
|
||||||
|
name := rt.Field(i).Name
|
||||||
|
wr.items = append(
|
||||||
|
wr.items,
|
||||||
|
nodeOf(
|
||||||
|
name,
|
||||||
|
": ",
|
||||||
|
reflectValue(
|
||||||
|
fieldOpts,
|
||||||
|
r.FieldByName(name),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, t, _ := withType(o); !t {
|
||||||
|
return nodeOf("{", wr, "}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf(reflectType(rt), "{", wr, "}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectUnsafePointer(o opts, r reflect.Value) node {
|
||||||
|
if r.IsNil() {
|
||||||
|
return reflectNil(o, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, _, a := withType(o); !a {
|
||||||
|
return nodeOf("pointer")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf(reflectType(r.Type()), "(pointer)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectValue(o opts, r reflect.Value) node {
|
||||||
|
switch r.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return reflectPrimitive(o, r, r.Bool(), "bool")
|
||||||
|
case
|
||||||
|
reflect.Int,
|
||||||
|
reflect.Int8,
|
||||||
|
reflect.Int16,
|
||||||
|
reflect.Int32,
|
||||||
|
reflect.Int64:
|
||||||
|
return reflectPrimitive(o, r, r.Int(), "int")
|
||||||
|
case
|
||||||
|
reflect.Uint,
|
||||||
|
reflect.Uint8,
|
||||||
|
reflect.Uint16,
|
||||||
|
reflect.Uint32,
|
||||||
|
reflect.Uint64,
|
||||||
|
reflect.Uintptr:
|
||||||
|
return reflectPrimitive(o, r, r.Uint())
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return reflectPrimitive(o, r, r.Float())
|
||||||
|
case reflect.Complex64, reflect.Complex128:
|
||||||
|
return reflectPrimitive(o, r, r.Complex())
|
||||||
|
case reflect.Array:
|
||||||
|
return reflectArray(o, r)
|
||||||
|
case reflect.Chan:
|
||||||
|
return reflectChan(o, r)
|
||||||
|
case reflect.Func:
|
||||||
|
return reflectFunc(o, r)
|
||||||
|
case reflect.Interface:
|
||||||
|
return reflectInterface(o, r)
|
||||||
|
case reflect.Map:
|
||||||
|
return reflectMap(o, r)
|
||||||
|
case reflect.Ptr:
|
||||||
|
return reflectPointer(o, r)
|
||||||
|
case reflect.Slice:
|
||||||
|
return reflectList(o, r)
|
||||||
|
case reflect.String:
|
||||||
|
return reflectString(o, r)
|
||||||
|
case reflect.Struct:
|
||||||
|
return reflectStruct(o, r)
|
||||||
|
case reflect.UnsafePointer:
|
||||||
|
return reflectUnsafePointer(o, r)
|
||||||
|
default:
|
||||||
|
return nodeOf("<invalid>")
|
||||||
|
}
|
||||||
|
}
|
129
reflecttype.go
Normal file
129
reflecttype.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package notation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
func reflectFuncBaseType(t reflect.Type) node {
|
||||||
|
args := func(num func() int, typ func(int) reflect.Type) []node {
|
||||||
|
var t []node
|
||||||
|
for i := 0; i < num(); i++ {
|
||||||
|
t = append(t, reflectType(typ(i)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
in := args(t.NumIn, t.In)
|
||||||
|
out := args(t.NumOut, t.Out)
|
||||||
|
|
||||||
|
n := nodeOf("(")
|
||||||
|
if len(in) == 1 {
|
||||||
|
n.parts = append(n.parts, in[0])
|
||||||
|
} else if len(in) > 1 {
|
||||||
|
n.parts = append(n.parts, wrapper{sep: ", ", items: in})
|
||||||
|
}
|
||||||
|
|
||||||
|
n.parts = append(n.parts, ")")
|
||||||
|
if len(out) == 1 {
|
||||||
|
n.parts = append(n.parts, " ", out[0])
|
||||||
|
} else if len(out) > 1 {
|
||||||
|
n.parts = append(n.parts, " (", wrapper{sep: ", ", items: out}, ")")
|
||||||
|
}
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectArrayType(t reflect.Type) node {
|
||||||
|
return nodeOf("[", t.Len(), "]", reflectType(t.Elem()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectChanType(t reflect.Type) node {
|
||||||
|
var prefix string
|
||||||
|
switch t.ChanDir() {
|
||||||
|
case reflect.RecvDir:
|
||||||
|
prefix = "<-chan "
|
||||||
|
case reflect.SendDir:
|
||||||
|
prefix = "chan<- "
|
||||||
|
default:
|
||||||
|
prefix = "chan "
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf(prefix, reflectType(t.Elem()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectFuncType(t reflect.Type) node {
|
||||||
|
return nodeOf("func", reflectFuncBaseType(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectInterfaceType(t reflect.Type) node {
|
||||||
|
wr := wrapper{sep: "; "}
|
||||||
|
for i := 0; i < t.NumMethod(); i++ {
|
||||||
|
method := t.Method(i)
|
||||||
|
wr.items = append(
|
||||||
|
wr.items,
|
||||||
|
nodeOf(
|
||||||
|
method.Name,
|
||||||
|
reflectFuncBaseType(method.Type),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf("interface{", wr, "}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectMapType(t reflect.Type) node {
|
||||||
|
return nodeOf("map[", reflectType(t.Key()), "]", reflectType(t.Elem()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectPointerType(t reflect.Type) node {
|
||||||
|
return nodeOf("*", reflectType(t.Elem()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectListType(t reflect.Type) node {
|
||||||
|
return nodeOf("[]", reflectType(t.Elem()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectStructType(t reflect.Type) node {
|
||||||
|
wr := wrapper{sep: "; "}
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
fi := t.Field(i)
|
||||||
|
wr.items = append(
|
||||||
|
wr.items,
|
||||||
|
nodeOf(
|
||||||
|
fi.Name,
|
||||||
|
" ",
|
||||||
|
reflectType(fi.Type),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeOf("struct{", wr, "}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectType(t reflect.Type) node {
|
||||||
|
if t.Name() != "" {
|
||||||
|
return nodeOf(t.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t.Kind() {
|
||||||
|
case reflect.Array:
|
||||||
|
return reflectArrayType(t)
|
||||||
|
case reflect.Chan:
|
||||||
|
return reflectChanType(t)
|
||||||
|
case reflect.Func:
|
||||||
|
return reflectFuncType(t)
|
||||||
|
case reflect.Interface:
|
||||||
|
return reflectInterfaceType(t)
|
||||||
|
case reflect.Map:
|
||||||
|
return reflectMapType(t)
|
||||||
|
case reflect.Ptr:
|
||||||
|
return reflectPointerType(t)
|
||||||
|
case reflect.Slice:
|
||||||
|
return reflectListType(t)
|
||||||
|
case reflect.Struct:
|
||||||
|
return reflectStructType(t)
|
||||||
|
default:
|
||||||
|
return nodeOf("<invalid>")
|
||||||
|
}
|
||||||
|
}
|
271
sprint.go
271
sprint.go
@ -1,271 +0,0 @@
|
|||||||
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>"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package notation
|
package notation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@ -243,8 +242,8 @@ func TestSprintv(t *testing.T) {
|
|||||||
{"structure", struct{ foo int }{42}, "struct{foo int}{foo: int(42)}"},
|
{"structure", struct{ foo int }{42}, "struct{foo int}{foo: int(42)}"},
|
||||||
{"custom structure", myStruct{42}, "myStruct{field: interface{}(int(42))}"},
|
{"custom structure", myStruct{42}, "myStruct{field: interface{}(int(42))}"},
|
||||||
{"custom structure, nil field", myStruct{}, "myStruct{field: interface{}(nil)}"},
|
{"custom structure, nil field", myStruct{}, "myStruct{field: interface{}(nil)}"},
|
||||||
{"unsafe pointer", unsafe.Pointer(&struct{}{}), "pointer"},
|
{"unsafe pointer", unsafe.Pointer(&struct{}{}), "Pointer(pointer)"},
|
||||||
{"custom unsafe pointer", myUnsafePointer(&struct{}{}), "pointer"},
|
{"custom unsafe pointer", myUnsafePointer(&struct{}{}), "myUnsafePointer(pointer)"},
|
||||||
{"unsafe pointer type", struct{ p unsafe.Pointer }{}, "struct{p Pointer}{p: Pointer(nil)}"},
|
{"unsafe pointer type", struct{ p unsafe.Pointer }{}, "struct{p Pointer}{p: Pointer(nil)}"},
|
||||||
} {
|
} {
|
||||||
t.Run(test.title, func(t *testing.T) {
|
t.Run(test.title, func(t *testing.T) {
|
||||||
@ -255,10 +254,3 @@ func TestSprintv(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSprintInvalid(t *testing.T) {
|
|
||||||
s := sprint(none, reflect.Value{})
|
|
||||||
if s != "<invalid>" {
|
|
||||||
t.Fatalf("expected: <invalid>, got: %s", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
118
type.go
118
type.go
@ -1,118 +0,0 @@
|
|||||||
package notation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func funcBase(t reflect.Type) string {
|
|
||||||
args := func(num func() int, typ func(int) reflect.Type) []string {
|
|
||||||
t := make([]string, num())
|
|
||||||
for i := 0; i < num(); i++ {
|
|
||||||
t[i] = sprintType(typ(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
in := args(t.NumIn, t.In)
|
|
||||||
out := args(t.NumOut, t.Out)
|
|
||||||
|
|
||||||
var outs string
|
|
||||||
if len(out) == 1 {
|
|
||||||
outs = out[0]
|
|
||||||
} else if len(out) > 1 {
|
|
||||||
outs = fmt.Sprintf("(%s)", strings.Join(out, ", "))
|
|
||||||
}
|
|
||||||
|
|
||||||
var s string
|
|
||||||
if outs == "" {
|
|
||||||
s = fmt.Sprintf("(%s)", strings.Join(in, ", "))
|
|
||||||
} else {
|
|
||||||
s = fmt.Sprintf("(%s) %s", strings.Join(in, ", "), outs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func arrayType(t reflect.Type) string {
|
|
||||||
return fmt.Sprintf("[%d]%s", t.Len(), sprintType(t.Elem()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func chanType(t reflect.Type) string {
|
|
||||||
var prefix string
|
|
||||||
switch t.ChanDir() {
|
|
||||||
case reflect.RecvDir:
|
|
||||||
prefix = "<-chan"
|
|
||||||
case reflect.SendDir:
|
|
||||||
prefix = "chan<-"
|
|
||||||
default:
|
|
||||||
prefix = "chan"
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s %s", prefix, sprintType(t.Elem()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func funcType(t reflect.Type) string {
|
|
||||||
return fmt.Sprintf("func%s", funcBase(t))
|
|
||||||
}
|
|
||||||
|
|
||||||
func interfaceType(t reflect.Type) string {
|
|
||||||
var m []string
|
|
||||||
for i := 0; i < t.NumMethod(); i++ {
|
|
||||||
method := t.Method(i)
|
|
||||||
m = append(m, fmt.Sprintf("%s%s", method.Name, funcBase(method.Type)))
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("interface{%s}", strings.Join(m, "; "))
|
|
||||||
}
|
|
||||||
|
|
||||||
func mapType(t reflect.Type) string {
|
|
||||||
return fmt.Sprintf("map[%s]%s", sprintType(t.Key()), sprintType(t.Elem()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func pointerType(t reflect.Type) string {
|
|
||||||
return fmt.Sprintf("*%s", sprintType(t.Elem()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func listType(t reflect.Type) string {
|
|
||||||
return fmt.Sprintf("[]%s", sprintType(t.Elem()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func structType(t reflect.Type) string {
|
|
||||||
f := make([]string, t.NumField())
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
|
||||||
fi := t.Field(i)
|
|
||||||
f[i] = fmt.Sprintf("%s %s", fi.Name, sprintType(fi.Type))
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("struct{%s}", strings.Join(f, "; "))
|
|
||||||
}
|
|
||||||
|
|
||||||
func sprintType(t reflect.Type) string {
|
|
||||||
if t.Name() != "" {
|
|
||||||
return t.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t.Kind() {
|
|
||||||
case reflect.Array:
|
|
||||||
return arrayType(t)
|
|
||||||
case reflect.Chan:
|
|
||||||
return chanType(t)
|
|
||||||
case reflect.Func:
|
|
||||||
return funcType(t)
|
|
||||||
case reflect.Interface:
|
|
||||||
return interfaceType(t)
|
|
||||||
case reflect.Map:
|
|
||||||
return mapType(t)
|
|
||||||
case reflect.Ptr:
|
|
||||||
return pointerType(t)
|
|
||||||
case reflect.Slice:
|
|
||||||
return listType(t)
|
|
||||||
case reflect.Struct:
|
|
||||||
return structType(t)
|
|
||||||
default:
|
|
||||||
return "<invalid>"
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user