mirror of
https://codeberg.org/scip/tablizer.git
synced 2025-12-18 04:51:05 +01:00
added
This commit is contained in:
21
vendor/github.com/shurcooL/go-goon/LICENSE
generated
vendored
Normal file
21
vendor/github.com/shurcooL/go-goon/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013 Dave Collins
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
92
vendor/github.com/shurcooL/go-goon/README.md
generated
vendored
Normal file
92
vendor/github.com/shurcooL/go-goon/README.md
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
goon
|
||||
====
|
||||
|
||||
[](https://pkg.go.dev/github.com/shurcooL/go-goon)
|
||||
|
||||
Package goon is a deep pretty printer with Go-like notation. It implements the [goon](https://github.com/shurcooL/goon) specification.
|
||||
|
||||
**Deprecated:** This package is old, incomplete, low code quality, and now unmaintained.
|
||||
See [github.com/hexops/valast](https://github.com/hexops/valast) for a newer package that is the closest known direct replacement.
|
||||
See the [Alternatives](#alternatives) section for other known entries in this problem space.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
```bash
|
||||
go get github.com/shurcooL/go-goon
|
||||
```
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
```Go
|
||||
x := Lang{
|
||||
Name: "Go",
|
||||
Year: 2009,
|
||||
URL: "http",
|
||||
Inner: &Inner{
|
||||
Field1: "Secret!",
|
||||
},
|
||||
}
|
||||
|
||||
goon.Dump(x)
|
||||
|
||||
// Output:
|
||||
// (Lang)(Lang{
|
||||
// Name: (string)("Go"),
|
||||
// Year: (int)(2009),
|
||||
// URL: (string)("http"),
|
||||
// Inner: (*Inner)(&Inner{
|
||||
// Field1: (string)("Secret!"),
|
||||
// Field2: (int)(0),
|
||||
// }),
|
||||
// })
|
||||
```
|
||||
|
||||
```Go
|
||||
items := []int{1, 2, 3}
|
||||
|
||||
goon.DumpExpr(len(items))
|
||||
|
||||
// Output:
|
||||
// len(items) = (int)(3)
|
||||
```
|
||||
|
||||
```Go
|
||||
adderFunc := func(a int, b int) int {
|
||||
c := a + b
|
||||
return c
|
||||
}
|
||||
|
||||
goon.DumpExpr(adderFunc)
|
||||
|
||||
// Output:
|
||||
// adderFunc = (func(int, int) int)(func(a int, b int) int {
|
||||
// c := a + b
|
||||
// return c
|
||||
// })
|
||||
```
|
||||
|
||||
Directories
|
||||
-----------
|
||||
|
||||
| Path | Synopsis |
|
||||
|-----------------------------------------------------------------|---------------------------------------------------------------------------------------------|
|
||||
| [bypass](https://pkg.go.dev/github.com/shurcooL/go-goon/bypass) | Package bypass allows bypassing reflect restrictions on accessing unexported struct fields. |
|
||||
|
||||
Alternatives
|
||||
------------
|
||||
|
||||
- [`go-spew`](https://github.com/davecgh/go-spew) - A deep pretty printer for Go data structures to aid in debugging.
|
||||
- [`valast`](https://github.com/hexops/valast) - Convert Go values to their AST.
|
||||
- [`repr`](https://github.com/alecthomas/repr) - Python's repr() for Go.
|
||||
|
||||
Attribution
|
||||
-----------
|
||||
|
||||
go-goon source was based on the existing source of [go-spew](https://github.com/davecgh/go-spew) by [Dave Collins](https://github.com/davecgh).
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
- [MIT License](LICENSE)
|
||||
394
vendor/github.com/shurcooL/go-goon/dump.go
generated
vendored
Normal file
394
vendor/github.com/shurcooL/go-goon/dump.go
generated
vendored
Normal file
@@ -0,0 +1,394 @@
|
||||
package goon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/shurcooL/go/reflectsource"
|
||||
)
|
||||
|
||||
var config = struct {
|
||||
indent string
|
||||
}{
|
||||
indent: "\t",
|
||||
}
|
||||
|
||||
// dumpState contains information about the state of a dump operation.
|
||||
type dumpState struct {
|
||||
w io.Writer
|
||||
depth int
|
||||
pointers map[uintptr]int
|
||||
ignoreNextType bool
|
||||
ignoreNextIndent bool
|
||||
}
|
||||
|
||||
// indent performs indentation according to the depth level and cs.Indent
|
||||
// option.
|
||||
func (d *dumpState) indent() {
|
||||
if d.ignoreNextIndent {
|
||||
d.ignoreNextIndent = false
|
||||
return
|
||||
}
|
||||
d.w.Write(bytes.Repeat([]byte(config.indent), d.depth))
|
||||
}
|
||||
|
||||
// unpackValue returns values inside of non-nil interfaces when possible.
|
||||
// This is useful for data types like structs, arrays, slices, and maps which
|
||||
// can contain varying types packed inside an interface.
|
||||
func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
|
||||
if v.Kind() == reflect.Interface && !v.IsNil() {
|
||||
v = v.Elem()
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// dumpPtr handles formatting of pointers by indirecting them as necessary.
|
||||
func (d *dumpState) dumpPtr(v reflect.Value) {
|
||||
// Remove pointers at or below the current depth from map used to detect
|
||||
// circular refs.
|
||||
for k, depth := range d.pointers {
|
||||
if depth >= d.depth {
|
||||
delete(d.pointers, k)
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out how many levels of indirection there are by dereferencing
|
||||
// pointers and unpacking interfaces down the chain while detecting circular
|
||||
// references.
|
||||
nilFound := false
|
||||
cycleFound := false
|
||||
indirects := 0
|
||||
ve := v
|
||||
for ve.Kind() == reflect.Ptr {
|
||||
if ve.IsNil() {
|
||||
nilFound = true
|
||||
break
|
||||
}
|
||||
indirects++
|
||||
addr := ve.Pointer()
|
||||
if pd, ok := d.pointers[addr]; ok && pd < d.depth {
|
||||
cycleFound = true
|
||||
indirects--
|
||||
break
|
||||
}
|
||||
d.pointers[addr] = d.depth
|
||||
|
||||
ve = ve.Elem()
|
||||
if ve.Kind() == reflect.Interface {
|
||||
if ve.IsNil() {
|
||||
nilFound = true
|
||||
break
|
||||
}
|
||||
ve = ve.Elem()
|
||||
}
|
||||
}
|
||||
|
||||
// Display type information.
|
||||
d.w.Write(bytes.Repeat(ampersandBytes, indirects))
|
||||
|
||||
// Display dereferenced value.
|
||||
switch {
|
||||
case nilFound:
|
||||
d.w.Write(nilBytes)
|
||||
|
||||
case cycleFound:
|
||||
d.w.Write(circularBytes)
|
||||
|
||||
default:
|
||||
d.ignoreNextType = true
|
||||
d.dump(ve)
|
||||
}
|
||||
}
|
||||
|
||||
// dump is the main workhorse for dumping a value. It uses the passed reflect
|
||||
// value to figure out what kind of object we are dealing with and formats it
|
||||
// appropriately. It is a recursive function, however circular data structures
|
||||
// are detected and handled properly.
|
||||
func (d *dumpState) dump(v reflect.Value) {
|
||||
// Handle invalid reflect values immediately.
|
||||
kind := v.Kind()
|
||||
if kind == reflect.Invalid {
|
||||
d.w.Write(invalidAngleBytes)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle pointers specially.
|
||||
if kind == reflect.Ptr {
|
||||
d.indent()
|
||||
d.w.Write(openParenBytes)
|
||||
d.w.Write([]byte(typeStringWithoutPackagePrefix(v)))
|
||||
d.w.Write(closeParenBytes)
|
||||
d.w.Write(openParenBytes)
|
||||
d.dumpPtr(v)
|
||||
d.w.Write(closeParenBytes)
|
||||
return
|
||||
}
|
||||
|
||||
// Print type information unless already handled elsewhere.
|
||||
var shouldPrintClosingBr = false
|
||||
if !d.ignoreNextType {
|
||||
d.indent()
|
||||
d.w.Write(openParenBytes)
|
||||
d.w.Write([]byte(typeStringWithoutPackagePrefix(v)))
|
||||
d.w.Write(closeParenBytes)
|
||||
d.w.Write(openParenBytes)
|
||||
shouldPrintClosingBr = true
|
||||
}
|
||||
d.ignoreNextType = false
|
||||
|
||||
if v.Type() == timeType {
|
||||
t := v.Interface().(time.Time)
|
||||
switch t.IsZero() {
|
||||
case false:
|
||||
var location string
|
||||
switch t.Location() {
|
||||
case time.UTC:
|
||||
location = "time.UTC"
|
||||
case time.Local:
|
||||
location = "time.Local"
|
||||
default:
|
||||
location = fmt.Sprintf("must(time.LoadLocation(%q))", t.Location().String())
|
||||
}
|
||||
fmt.Fprintf(d.w, "time.Date(%d, %d, %d, %d, %d, %d, %d, %s)", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), location)
|
||||
case true:
|
||||
d.w.Write([]byte("time.Time{}"))
|
||||
}
|
||||
goto AfterKindSwitch
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Invalid:
|
||||
// Do nothing. We should never get here since invalid has already
|
||||
// been handled above.
|
||||
|
||||
case reflect.Bool:
|
||||
printBool(d.w, v.Bool())
|
||||
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||
printInt(d.w, v.Int(), 10)
|
||||
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
printUint(d.w, v.Uint(), 10)
|
||||
|
||||
case reflect.Float32:
|
||||
printFloat(d.w, v.Float(), 32)
|
||||
|
||||
case reflect.Float64:
|
||||
printFloat(d.w, v.Float(), 64)
|
||||
|
||||
case reflect.Complex64:
|
||||
printComplex(d.w, v.Complex(), 32)
|
||||
|
||||
case reflect.Complex128:
|
||||
printComplex(d.w, v.Complex(), 64)
|
||||
|
||||
case reflect.Array:
|
||||
d.w.Write([]byte(typeStringWithoutPackagePrefix(v)))
|
||||
d.w.Write(openBraceNewlineBytes)
|
||||
d.depth++
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
d.dump(d.unpackValue(v.Index(i)))
|
||||
d.w.Write(commaNewlineBytes)
|
||||
}
|
||||
d.depth--
|
||||
d.indent()
|
||||
d.w.Write(closeBraceBytes)
|
||||
|
||||
case reflect.Slice:
|
||||
if v.IsNil() {
|
||||
d.w.Write(nilBytes)
|
||||
} else {
|
||||
d.w.Write([]byte(typeStringWithoutPackagePrefix(v)))
|
||||
d.w.Write(openBraceNewlineBytes)
|
||||
d.depth++
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
d.dump(d.unpackValue(v.Index(i)))
|
||||
d.w.Write(commaNewlineBytes)
|
||||
}
|
||||
d.depth--
|
||||
d.indent()
|
||||
d.w.Write(closeBraceBytes)
|
||||
}
|
||||
|
||||
case reflect.String:
|
||||
d.w.Write([]byte(strconv.Quote(v.String())))
|
||||
|
||||
case reflect.Interface:
|
||||
// If we got here, it's because interface is nil
|
||||
// See https://github.com/davecgh/go-spew/issues/12
|
||||
d.w.Write(nilBytes)
|
||||
|
||||
case reflect.Ptr:
|
||||
// Do nothing. We should never get here since pointers have already
|
||||
// been handled above.
|
||||
|
||||
case reflect.Map:
|
||||
if v.IsNil() {
|
||||
d.w.Write(nilBytes)
|
||||
} else {
|
||||
d.w.Write([]byte(typeStringWithoutPackagePrefix(v)))
|
||||
d.w.Write(openBraceNewlineBytes)
|
||||
d.depth++
|
||||
keys := v.MapKeys()
|
||||
for _, key := range keys {
|
||||
d.dump(d.unpackValue(key))
|
||||
d.w.Write(colonSpaceBytes)
|
||||
d.ignoreNextIndent = true
|
||||
d.dump(d.unpackValue(v.MapIndex(key)))
|
||||
d.w.Write(commaNewlineBytes)
|
||||
}
|
||||
d.depth--
|
||||
d.indent()
|
||||
d.w.Write(closeBraceBytes)
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
d.w.Write([]byte(typeStringWithoutPackagePrefix(v)))
|
||||
d.w.Write(openBraceBytes)
|
||||
d.depth++
|
||||
{
|
||||
vt := v.Type()
|
||||
numFields := v.NumField()
|
||||
if numFields > 0 {
|
||||
d.w.Write(newlineBytes)
|
||||
}
|
||||
for i := 0; i < numFields; i++ {
|
||||
d.indent()
|
||||
vtf := vt.Field(i)
|
||||
d.w.Write([]byte(vtf.Name))
|
||||
d.w.Write(colonSpaceBytes)
|
||||
d.ignoreNextIndent = true
|
||||
d.dump(d.unpackValue(v.Field(i)))
|
||||
d.w.Write(commaBytes)
|
||||
d.w.Write(newlineBytes)
|
||||
}
|
||||
}
|
||||
d.depth--
|
||||
d.indent()
|
||||
d.w.Write(closeBraceBytes)
|
||||
|
||||
case reflect.Uintptr:
|
||||
printHexPtr(d.w, uintptr(v.Uint()))
|
||||
|
||||
case reflect.Func:
|
||||
d.w.Write([]byte(reflectsource.GetFuncValueSourceAsString(v)))
|
||||
|
||||
case reflect.UnsafePointer, reflect.Chan:
|
||||
printHexPtr(d.w, v.Pointer())
|
||||
|
||||
// There were not any other types at the time this code was written, but
|
||||
// fall back to letting the default fmt package handle it in case any new
|
||||
// types are added.
|
||||
default:
|
||||
if v.CanInterface() {
|
||||
fmt.Fprintf(d.w, "%v", v.Interface())
|
||||
} else {
|
||||
fmt.Fprintf(d.w, "%v", v.String())
|
||||
}
|
||||
}
|
||||
AfterKindSwitch:
|
||||
|
||||
if shouldPrintClosingBr {
|
||||
d.w.Write(closeParenBytes)
|
||||
}
|
||||
}
|
||||
|
||||
var timeType = reflect.TypeOf(time.Time{})
|
||||
|
||||
func typeStringWithoutPackagePrefix(v reflect.Value) string {
|
||||
//return v.Type().String()[len(v.Type().PkgPath())+1:] // TODO: Error checking?
|
||||
//return v.Type().PkgPath()
|
||||
//return v.Type().String()
|
||||
//return v.Type().Name()
|
||||
|
||||
/*x := v.Type().String()
|
||||
if strings.HasPrefix(x, "main.") {
|
||||
x = x[len("main."):]
|
||||
}
|
||||
return x*/
|
||||
|
||||
px := v.Type().String()
|
||||
prefix := px[0 : len(px)-len(strings.TrimLeft(px, "*"))] // Split "**main.Lang" -> "**" and "main.Lang"
|
||||
x := px[len(prefix):]
|
||||
x = strings.TrimPrefix(x, "main.")
|
||||
x = strings.TrimPrefix(x, "goon_test.")
|
||||
return prefix + x
|
||||
|
||||
/*x = string(debug.Stack())//GetLine(string(debug.Stack()), 0)
|
||||
//x = x[1:strings.Index(x, ":")]
|
||||
//spew.Printf(">%s<\n", x)
|
||||
//panic(nil)
|
||||
//st := string(debug.Stack())
|
||||
//debug.PrintStack()
|
||||
|
||||
return x*/
|
||||
}
|
||||
|
||||
// fdump is a helper function to consolidate the logic from the various public
|
||||
// methods which take varying writers and config states.
|
||||
func fdump(w io.Writer, a ...interface{}) {
|
||||
for _, arg := range a {
|
||||
d := dumpState{w: w}
|
||||
if arg == nil {
|
||||
d.w.Write(interfaceBytes)
|
||||
d.w.Write(nilParenBytes)
|
||||
} else {
|
||||
d.pointers = make(map[uintptr]int)
|
||||
d.dump(reflect.ValueOf(arg))
|
||||
}
|
||||
d.w.Write(newlineBytes)
|
||||
}
|
||||
}
|
||||
|
||||
// bdump dumps to []byte.
|
||||
func bdump(a ...interface{}) []byte {
|
||||
var buf bytes.Buffer
|
||||
fdump(&buf, a...)
|
||||
return gofmt(buf.Bytes())
|
||||
}
|
||||
|
||||
func fdumpNamed(w io.Writer, names []string, a ...interface{}) {
|
||||
for argIndex, arg := range a {
|
||||
d := dumpState{w: w}
|
||||
if argIndex < len(names) {
|
||||
d.w.Write([]byte(names[argIndex]))
|
||||
d.w.Write([]byte(" = "))
|
||||
}
|
||||
if arg == nil {
|
||||
d.w.Write(interfaceBytes)
|
||||
d.w.Write(nilParenBytes)
|
||||
} else {
|
||||
d.pointers = make(map[uintptr]int)
|
||||
d.dump(reflect.ValueOf(arg))
|
||||
}
|
||||
if len(names) >= len(a) {
|
||||
d.w.Write(newlineBytes)
|
||||
} else {
|
||||
if argIndex < len(a)-1 {
|
||||
d.w.Write(commaNewlineBytes)
|
||||
} else {
|
||||
d.w.Write(newlineBytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func bdumpNamed(names []string, a ...interface{}) []byte {
|
||||
var buf bytes.Buffer
|
||||
fdumpNamed(&buf, names, a...)
|
||||
return gofmt(buf.Bytes())
|
||||
}
|
||||
|
||||
func gofmt(src []byte) []byte {
|
||||
formattedSrc, err := format.Source(src)
|
||||
if nil != err {
|
||||
return []byte("gofmt error (" + err.Error() + ")!\n" + string(src))
|
||||
}
|
||||
return formattedSrc
|
||||
}
|
||||
56
vendor/github.com/shurcooL/go-goon/goon.go
generated
vendored
Normal file
56
vendor/github.com/shurcooL/go-goon/goon.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Package goon is a deep pretty printer with Go-like notation. It implements the goon specification.
|
||||
//
|
||||
// Deprecated: This package is old, incomplete, low code quality, and now unmaintained.
|
||||
// See github.com/hexops/valast for a newer package that is the closest known direct replacement.
|
||||
// See the Alternatives section in README.md for other known entries in this problem space.
|
||||
package goon
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/shurcooL/go/reflectsource"
|
||||
)
|
||||
|
||||
// Dump dumps goons to stdout.
|
||||
func Dump(a ...interface{}) (n int, err error) {
|
||||
return os.Stdout.Write(bdump(a...))
|
||||
}
|
||||
|
||||
// Sdump dumps goons to a string.
|
||||
func Sdump(a ...interface{}) string {
|
||||
return string(bdump(a...))
|
||||
}
|
||||
|
||||
// Fdump dumps goons to a writer.
|
||||
func Fdump(w io.Writer, a ...interface{}) (n int, err error) {
|
||||
return w.Write(bdump(a...))
|
||||
}
|
||||
|
||||
// DumpExpr dumps goon expressions to stdout.
|
||||
//
|
||||
// E.g., this:
|
||||
//
|
||||
// somethingImportant := 5
|
||||
// DumpExpr(somethingImportant)
|
||||
//
|
||||
// Will print:
|
||||
//
|
||||
// somethingImportant = (int)(5)
|
||||
func DumpExpr(a ...interface{}) (n int, err error) {
|
||||
return os.Stdout.Write(bdumpNamed(reflectsource.GetParentArgExprAllAsString(), a...))
|
||||
}
|
||||
|
||||
// SdumpExpr dumps goon expressions to a string.
|
||||
func SdumpExpr(a ...interface{}) string {
|
||||
return string(bdumpNamed(reflectsource.GetParentArgExprAllAsString(), a...))
|
||||
}
|
||||
|
||||
// FdumpExpr dumps goon expressions to a writer.
|
||||
func FdumpExpr(w io.Writer, a ...interface{}) (n int, err error) {
|
||||
names := reflectsource.GetParentArgExprAllAsString()
|
||||
if len(names) >= 1 {
|
||||
names = names[1:] // First argument is the writer, skip it.
|
||||
}
|
||||
return w.Write(bdumpNamed(names, a...))
|
||||
}
|
||||
107
vendor/github.com/shurcooL/go-goon/print_types.go
generated
vendored
Normal file
107
vendor/github.com/shurcooL/go-goon/print_types.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
package goon
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Some constants in the form of bytes to avoid string overhead. This mirrors
|
||||
// the technique used in the fmt package.
|
||||
var (
|
||||
plusBytes = []byte("+")
|
||||
iBytes = []byte("i")
|
||||
trueBytes = []byte("true")
|
||||
falseBytes = []byte("false")
|
||||
interfaceBytes = []byte("(interface{})")
|
||||
commaBytes = []byte(",")
|
||||
commaNewlineBytes = []byte(",\n")
|
||||
newlineBytes = []byte("\n")
|
||||
openBraceBytes = []byte("{")
|
||||
openBraceNewlineBytes = []byte("{\n")
|
||||
closeBraceBytes = []byte("}")
|
||||
ampersandBytes = []byte("&")
|
||||
colonSpaceBytes = []byte(": ")
|
||||
openParenBytes = []byte("(")
|
||||
closeParenBytes = []byte(")")
|
||||
nilBytes = []byte("nil")
|
||||
nilParenBytes = []byte("(nil)")
|
||||
circularBytes = []byte("already_shown")
|
||||
invalidAngleBytes = []byte("<invalid>")
|
||||
)
|
||||
|
||||
// hexDigits is used to map a decimal value to a hex digit.
|
||||
var hexDigits = "0123456789abcdef"
|
||||
|
||||
// printBool outputs a boolean value as true or false to Writer w.
|
||||
func printBool(w io.Writer, val bool) {
|
||||
if val {
|
||||
w.Write(trueBytes)
|
||||
} else {
|
||||
w.Write(falseBytes)
|
||||
}
|
||||
}
|
||||
|
||||
// printInt outputs a signed integer value to Writer w.
|
||||
func printInt(w io.Writer, val int64, base int) {
|
||||
w.Write([]byte(strconv.FormatInt(val, base)))
|
||||
}
|
||||
|
||||
// printUint outputs an unsigned integer value to Writer w.
|
||||
func printUint(w io.Writer, val uint64, base int) {
|
||||
w.Write([]byte(strconv.FormatUint(val, base)))
|
||||
}
|
||||
|
||||
// printFloat outputs a floating point value using the specified precision,
|
||||
// which is expected to be 32 or 64bit, to Writer w.
|
||||
func printFloat(w io.Writer, val float64, precision int) {
|
||||
w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
|
||||
}
|
||||
|
||||
// printComplex outputs a complex value using the specified float precision
|
||||
// for the real and imaginary parts to Writer w.
|
||||
func printComplex(w io.Writer, c complex128, floatPrecision int) {
|
||||
r := real(c)
|
||||
w.Write(openParenBytes)
|
||||
w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
|
||||
i := imag(c)
|
||||
if i >= 0 {
|
||||
w.Write(plusBytes)
|
||||
}
|
||||
w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
|
||||
w.Write(iBytes)
|
||||
w.Write(closeParenBytes)
|
||||
}
|
||||
|
||||
// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
|
||||
// prefix to Writer w.
|
||||
func printHexPtr(w io.Writer, p uintptr) {
|
||||
// Null pointer.
|
||||
num := uint64(p)
|
||||
if num == 0 {
|
||||
w.Write(nilBytes)
|
||||
return
|
||||
}
|
||||
|
||||
// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
|
||||
buf := make([]byte, 18)
|
||||
|
||||
// It's simpler to construct the hex string right to left.
|
||||
base := uint64(16)
|
||||
i := len(buf) - 1
|
||||
for num >= base {
|
||||
buf[i] = hexDigits[num%base]
|
||||
num /= base
|
||||
i--
|
||||
}
|
||||
buf[i] = hexDigits[num]
|
||||
|
||||
// Add '0x' prefix.
|
||||
i--
|
||||
buf[i] = 'x'
|
||||
i--
|
||||
buf[i] = '0'
|
||||
|
||||
// Strip unused leading bytes.
|
||||
buf = buf[i:]
|
||||
w.Write(buf)
|
||||
}
|
||||
21
vendor/github.com/shurcooL/go/LICENSE
generated
vendored
Normal file
21
vendor/github.com/shurcooL/go/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013 Dmitri Shuralyov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
34
vendor/github.com/shurcooL/go/parserutil/parserutil.go
generated
vendored
Normal file
34
vendor/github.com/shurcooL/go/parserutil/parserutil.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Package parserutil offers convenience functions for parsing Go code to AST.
|
||||
package parserutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
)
|
||||
|
||||
// ParseStmt is a convenience function for obtaining the AST of a statement x.
|
||||
// The position information recorded in the AST is undefined. The filename used
|
||||
// in error messages is the empty string.
|
||||
func ParseStmt(x string) (ast.Stmt, error) {
|
||||
file, err := parser.ParseFile(token.NewFileSet(), "", "package p;func _(){\n//line :1\n"+x+"\n;}", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return file.Decls[0].(*ast.FuncDecl).Body.List[0], nil
|
||||
}
|
||||
|
||||
// ParseDecl is a convenience function for obtaining the AST of a declaration x.
|
||||
// The position information recorded in the AST is undefined. The filename used
|
||||
// in error messages is the empty string.
|
||||
func ParseDecl(x string) (ast.Decl, error) {
|
||||
file, err := parser.ParseFile(token.NewFileSet(), "", "package p\n//line :1\n"+x+"\n", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(file.Decls) == 0 {
|
||||
return nil, errors.New("no declaration")
|
||||
}
|
||||
return file.Decls[0], nil
|
||||
}
|
||||
36
vendor/github.com/shurcooL/go/printerutil/printerutil.go
generated
vendored
Normal file
36
vendor/github.com/shurcooL/go/printerutil/printerutil.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Package printerutil provides formatted printing of AST nodes.
|
||||
package printerutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
)
|
||||
|
||||
// Consistent with the default gofmt behavior.
|
||||
var config = printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
|
||||
|
||||
// SprintAst prints node, using fset, and returns it as string.
|
||||
func SprintAst(fset *token.FileSet, node interface{}) string {
|
||||
var buf bytes.Buffer
|
||||
config.Fprint(&buf, fset, node)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// SprintAstBare prints node and returns it as string.
|
||||
func SprintAstBare(node interface{}) string {
|
||||
fset := token.NewFileSet()
|
||||
return SprintAst(fset, node)
|
||||
}
|
||||
|
||||
// PrintlnAst prints node, using fset, to stdout.
|
||||
func PrintlnAst(fset *token.FileSet, node interface{}) {
|
||||
fmt.Println(SprintAst(fset, node))
|
||||
}
|
||||
|
||||
// PrintlnAstBare prints node to stdout.
|
||||
func PrintlnAstBare(node interface{}) {
|
||||
fset := token.NewFileSet()
|
||||
PrintlnAst(fset, node)
|
||||
}
|
||||
112
vendor/github.com/shurcooL/go/reflectfind/reflectfind.go
generated
vendored
Normal file
112
vendor/github.com/shurcooL/go/reflectfind/reflectfind.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
// Package reflectfind offers funcs to perform deep-search via reflect to find instances that satisfy given query.
|
||||
package reflectfind
|
||||
|
||||
import "reflect"
|
||||
|
||||
// First finds the first instances of i that satisfies query within d.
|
||||
func First(d interface{}, query func(i interface{}) bool) interface{} {
|
||||
s := state{Visited: make(map[uintptr]struct{})}
|
||||
return s.findFirst(reflect.ValueOf(d), query)
|
||||
}
|
||||
|
||||
type state struct {
|
||||
Visited map[uintptr]struct{}
|
||||
}
|
||||
|
||||
func (s *state) findFirst(v reflect.Value, query func(i interface{}) bool) interface{} {
|
||||
// TODO: Should I check v.CanInterface()? It seems like I might be able to get away without it...
|
||||
if query(v.Interface()) {
|
||||
return v.Interface()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if q := s.findFirst(v.Field(i), query); q != nil {
|
||||
return q
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
for _, key := range v.MapKeys() {
|
||||
if q := s.findFirst(v.MapIndex(key), query); q != nil {
|
||||
return q
|
||||
}
|
||||
}
|
||||
case reflect.Array, reflect.Slice:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if q := s.findFirst(v.Index(i), query); q != nil {
|
||||
return q
|
||||
}
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if !v.IsNil() {
|
||||
if _, visited := s.Visited[v.Pointer()]; !visited {
|
||||
s.Visited[v.Pointer()] = struct{}{}
|
||||
if q := s.findFirst(v.Elem(), query); q != nil {
|
||||
return q
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Interface:
|
||||
if !v.IsNil() {
|
||||
if q := s.findFirst(v.Elem(), query); q != nil {
|
||||
return q
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// All finds all instances of i that satisfy query within d.
|
||||
func All(d interface{}, query func(i interface{}) bool) map[interface{}]struct{} {
|
||||
s := stateAll{state: state{Visited: make(map[uintptr]struct{})}, Found: make(map[interface{}]struct{})}
|
||||
s.findAll(reflect.ValueOf(d), query)
|
||||
return s.Found
|
||||
}
|
||||
|
||||
type stateAll struct {
|
||||
state
|
||||
Found map[interface{}]struct{}
|
||||
}
|
||||
|
||||
func (s *stateAll) findAll(v reflect.Value, query func(i interface{}) bool) {
|
||||
switch v.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
// TODO: Instead of skipping nil values, maybe pass the info as a bool parameter to query?
|
||||
if v.IsNil() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should I check v.CanInterface()? It seems like I might be able to get away without it...
|
||||
if query(v.Interface()) {
|
||||
s.Found[v.Interface()] = struct{}{}
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
s.findAll(v.Field(i), query)
|
||||
}
|
||||
case reflect.Map:
|
||||
for _, key := range v.MapKeys() {
|
||||
s.findAll(v.MapIndex(key), query)
|
||||
}
|
||||
case reflect.Array, reflect.Slice:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
s.findAll(v.Index(i), query)
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if !v.IsNil() {
|
||||
if _, visited := s.Visited[v.Pointer()]; !visited {
|
||||
s.Visited[v.Pointer()] = struct{}{}
|
||||
s.findAll(v.Elem(), query)
|
||||
}
|
||||
}
|
||||
case reflect.Interface:
|
||||
if !v.IsNil() {
|
||||
s.findAll(v.Elem(), query)
|
||||
}
|
||||
}
|
||||
}
|
||||
219
vendor/github.com/shurcooL/go/reflectsource/callername.go
generated
vendored
Normal file
219
vendor/github.com/shurcooL/go/reflectsource/callername.go
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
package reflectsource
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/shurcooL/go/parserutil"
|
||||
"github.com/shurcooL/go/printerutil"
|
||||
"github.com/shurcooL/go/reflectfind"
|
||||
)
|
||||
|
||||
// GetParentFuncAsString gets the parent func as a string.
|
||||
func GetParentFuncAsString() string {
|
||||
// TODO: Replace use of debug.Stack() with direct use of runtime package...
|
||||
// TODO: Use runtime.FuncForPC(runtime.Caller()).Name() to get func name if source code not found.
|
||||
stack := string(stack())
|
||||
|
||||
funcName := getLine(stack, 3)
|
||||
funcName = funcName[1:strings.Index(funcName, ": ")]
|
||||
if dotPos := strings.LastIndex(funcName, "."); dotPos != -1 { // Trim package prefix.
|
||||
funcName = funcName[dotPos+1:]
|
||||
}
|
||||
|
||||
funcArgs := getLine(stack, 5)
|
||||
funcArgs = funcArgs[strings.Index(funcArgs, ": ")+len(": "):]
|
||||
funcArgs = funcArgs[strings.Index(funcArgs, "(") : strings.LastIndex(funcArgs, ")")+len(")")] // TODO: This may fail if there are 2+ func calls on one line.
|
||||
|
||||
return funcName + funcArgs
|
||||
}
|
||||
|
||||
// GetParentFuncArgsAsString gets the parent func with its args as a string.
|
||||
func GetParentFuncArgsAsString(args ...interface{}) string {
|
||||
// TODO: Replace use of debug.Stack() with direct use of runtime package...
|
||||
// TODO: Use runtime.FuncForPC(runtime.Caller()).Name() to get func name if source code not found.
|
||||
stack := string(stack())
|
||||
|
||||
funcName := getLine(stack, 3)
|
||||
funcName = funcName[1:strings.Index(funcName, ": ")]
|
||||
if dotPos := strings.LastIndex(funcName, "."); dotPos != -1 { // Trim package prefix.
|
||||
funcName = funcName[dotPos+1:]
|
||||
}
|
||||
|
||||
funcArgs := "("
|
||||
for i, arg := range args {
|
||||
// TODO: Add arg names. Maybe not?
|
||||
if i != 0 {
|
||||
funcArgs += ", "
|
||||
}
|
||||
funcArgs += fmt.Sprintf("%#v", arg) // TODO: Maybe use goon instead. Need to move elsewhere to avoid import cycle.
|
||||
}
|
||||
funcArgs += ")"
|
||||
|
||||
return funcName + funcArgs
|
||||
}
|
||||
|
||||
// GetExprAsString gets the expression as a string.
|
||||
func GetExprAsString(_ interface{}) string {
|
||||
return GetParentArgExprAsString(0)
|
||||
}
|
||||
|
||||
func getParent2ArgExprAllAsAst() []ast.Expr {
|
||||
// TODO: Replace use of debug.Stack() with direct use of runtime package...
|
||||
stack := string(stack())
|
||||
|
||||
// TODO: Bounds error checking, get rid of GetLine gists, etc.
|
||||
parentName := getLine(stack, 5)
|
||||
if !strings.Contains(parentName, ": ") {
|
||||
// TODO: This happens when source file isn't present in same location as when built. See if can do anything better
|
||||
// via direct use of runtime package (instead of debug.Stack(), which will exclude any func names)...
|
||||
return nil
|
||||
}
|
||||
parentName = parentName[1:strings.Index(parentName, ": ")]
|
||||
if dotPos := strings.LastIndex(parentName, "."); dotPos != -1 { // Trim package prefix.
|
||||
parentName = parentName[dotPos+1:]
|
||||
}
|
||||
|
||||
str := getLine(stack, 7)
|
||||
str = str[strings.Index(str, ": ")+len(": "):]
|
||||
p, err := parserutil.ParseStmt(str)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
innerQuery := func(i interface{}) bool {
|
||||
if ident, ok := i.(*ast.Ident); ok && ident.Name == parentName {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
query := func(i interface{}) bool {
|
||||
if c, ok := i.(*ast.CallExpr); ok && nil != reflectfind.First(c.Fun, innerQuery) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
callExpr, _ := reflectfind.First(p, query).(*ast.CallExpr)
|
||||
|
||||
if callExpr == nil {
|
||||
return nil
|
||||
}
|
||||
return callExpr.Args
|
||||
}
|
||||
|
||||
// GetParentArgExprAsString gets the argIndex argument expression of parent func call as a string.
|
||||
func GetParentArgExprAsString(argIndex uint32) string {
|
||||
args := getParent2ArgExprAllAsAst()
|
||||
if args == nil {
|
||||
return "<expr not found>"
|
||||
}
|
||||
if argIndex >= uint32(len(args)) {
|
||||
return "<out of range>"
|
||||
}
|
||||
|
||||
return printerutil.SprintAstBare(args[argIndex])
|
||||
}
|
||||
|
||||
// GetParentArgExprAllAsString gets all argument expressions of parent func call as a string.
|
||||
func GetParentArgExprAllAsString() []string {
|
||||
args := getParent2ArgExprAllAsAst()
|
||||
if args == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
out := make([]string, len(args))
|
||||
for i := range args {
|
||||
out[i] = printerutil.SprintAstBare(args[i])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func getMySecondArgExprAsString(int, int) string {
|
||||
return GetParentArgExprAsString(1)
|
||||
}
|
||||
|
||||
func getLine(s string, lineIndex int) string {
|
||||
return strings.Split(s, "\n")[lineIndex]
|
||||
}
|
||||
|
||||
var (
|
||||
dunno = []byte("???")
|
||||
centerDot = []byte("·")
|
||||
dot = []byte(".")
|
||||
slash = []byte("/")
|
||||
)
|
||||
|
||||
// stack returns a formatted stack trace of the goroutine that calls it.
|
||||
// For each routine, it includes the source line information and PC value,
|
||||
// then attempts to discover, for Go functions, the calling function or
|
||||
// method and the text of the line containing the invocation.
|
||||
//
|
||||
// It was deprecated in Go 1.5, suggested to use package runtime's Stack instead,
|
||||
// and replaced by another implementation in Go 1.6.
|
||||
//
|
||||
// stack implements the Go 1.5 version of debug.Stack(), skipping 1 frame,
|
||||
// instead of 2, since it's being called directly (rather than via debug.Stack()).
|
||||
func stack() []byte {
|
||||
buf := new(bytes.Buffer) // the returned data
|
||||
// As we loop, we open files and read them. These variables record the currently
|
||||
// loaded file.
|
||||
var lines [][]byte
|
||||
var lastFile string
|
||||
for i := 1; ; i++ { // Caller we care about is the user, 1 frame up
|
||||
pc, file, line, ok := runtime.Caller(i)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
// Print this much at least. If we can't find the source, it won't show.
|
||||
fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
|
||||
if file != lastFile {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
lines = bytes.Split(data, []byte{'\n'})
|
||||
lastFile = file
|
||||
}
|
||||
line-- // in stack trace, lines are 1-indexed but our array is 0-indexed
|
||||
fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// source returns a space-trimmed slice of the n'th line.
|
||||
func source(lines [][]byte, n int) []byte {
|
||||
if n < 0 || n >= len(lines) {
|
||||
return dunno
|
||||
}
|
||||
return bytes.Trim(lines[n], " \t")
|
||||
}
|
||||
|
||||
// function returns, if possible, the name of the function containing the PC.
|
||||
func function(pc uintptr) []byte {
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn == nil {
|
||||
return dunno
|
||||
}
|
||||
name := []byte(fn.Name())
|
||||
// The name includes the path name to the package, which is unnecessary
|
||||
// since the file name is already included. Plus, it has center dots.
|
||||
// That is, we see
|
||||
// runtime/debug.*T·ptrmethod
|
||||
// and want
|
||||
// *T.ptrmethod
|
||||
// Since the package path might contains dots (e.g. code.google.com/...),
|
||||
// we first remove the path prefix if there is one.
|
||||
if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
|
||||
name = name[lastslash+1:]
|
||||
}
|
||||
if period := bytes.Index(name, dot); period >= 0 {
|
||||
name = name[period+1:]
|
||||
}
|
||||
name = bytes.Replace(name, centerDot, dot, -1)
|
||||
return name
|
||||
}
|
||||
9
vendor/github.com/shurcooL/go/reflectsource/doc.go
generated
vendored
Normal file
9
vendor/github.com/shurcooL/go/reflectsource/doc.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Package sourcereflect implements run-time source reflection, allowing a program to
|
||||
// look up string representation of objects from the underlying .go source files.
|
||||
//
|
||||
// Specifically, it implements ability to get name of caller funcs and their parameters.
|
||||
// It also implements functionality to get a string containing source code of provided func.
|
||||
//
|
||||
// In order to succeed, it expects the program's source code to be available in normal location.
|
||||
// It's intended to be used for development purposes, or for experimental programs.
|
||||
package reflectsource
|
||||
82
vendor/github.com/shurcooL/go/reflectsource/funcsource.go
generated
vendored
Normal file
82
vendor/github.com/shurcooL/go/reflectsource/funcsource.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
package reflectsource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
||||
"github.com/shurcooL/go/printerutil"
|
||||
"github.com/shurcooL/go/reflectfind"
|
||||
)
|
||||
|
||||
// GetSourceAsString returns the source of the func f.
|
||||
func GetSourceAsString(f interface{}) string {
|
||||
// No need to check for f being nil, since that's handled below.
|
||||
fv := reflect.ValueOf(f)
|
||||
return GetFuncValueSourceAsString(fv)
|
||||
}
|
||||
|
||||
// GetFuncValueSourceAsString returns the source of the func value fv.
|
||||
func GetFuncValueSourceAsString(fv reflect.Value) string {
|
||||
// Checking the kind catches cases where f was nil, resulting in fv being a zero Value (i.e. invalid kind),
|
||||
// as well as when fv is non-func.
|
||||
if fv.Kind() != reflect.Func {
|
||||
return "kind not func"
|
||||
}
|
||||
pc := fv.Pointer()
|
||||
if pc == 0 {
|
||||
return "nil"
|
||||
}
|
||||
function := runtime.FuncForPC(pc)
|
||||
if function == nil {
|
||||
return "nil"
|
||||
}
|
||||
file, line := function.FileLine(pc)
|
||||
|
||||
var startIndex, endIndex int
|
||||
{
|
||||
b, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return "<file not found>"
|
||||
}
|
||||
startIndex, endIndex = getLineStartEndIndicies(b, line-1)
|
||||
}
|
||||
|
||||
fs := token.NewFileSet()
|
||||
fileAst, err := parser.ParseFile(fs, file, nil, 0*parser.ParseComments)
|
||||
if err != nil {
|
||||
return "<ParseFile failed>"
|
||||
}
|
||||
|
||||
// TODO: Consider using ast.Walk() instead of custom FindFirst()
|
||||
query := func(i interface{}) bool {
|
||||
// TODO: Factor-out the unusual overlap check
|
||||
if f, ok := i.(*ast.FuncLit); ok && ((startIndex <= int(f.Pos())-1 && int(f.Pos())-1 <= endIndex) || (int(f.Pos())-1 <= startIndex && startIndex <= int(f.End())-1)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
funcAst := reflectfind.First(fileAst, query)
|
||||
|
||||
// If func literal wasn't found, try again looking for func declaration
|
||||
if funcAst == nil {
|
||||
query := func(i interface{}) bool {
|
||||
// TODO: Factor-out the unusual overlap check
|
||||
if f, ok := i.(*ast.FuncDecl); ok && ((startIndex <= int(f.Pos())-1 && int(f.Pos())-1 <= endIndex) || (int(f.Pos())-1 <= startIndex && startIndex <= int(f.End())-1)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
funcAst = reflectfind.First(fileAst, query)
|
||||
}
|
||||
|
||||
if funcAst == nil {
|
||||
return fmt.Sprintf("<func src not found at %v:%v>", file, line)
|
||||
}
|
||||
|
||||
return printerutil.SprintAst(fs, funcAst)
|
||||
}
|
||||
29
vendor/github.com/shurcooL/go/reflectsource/indicies.go
generated
vendored
Normal file
29
vendor/github.com/shurcooL/go/reflectsource/indicies.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package reflectsource
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// getLineStartEndIndicies gets the starting and ending caret indicies of line with specified lineIndex.
|
||||
// Does not include newline character.
|
||||
// First line has index 0.
|
||||
// Returns (-1, -1) if line is not found.
|
||||
func getLineStartEndIndicies(b []byte, lineIndex int) (startIndex, endIndex int) {
|
||||
index := 0
|
||||
for line := 0; ; line++ {
|
||||
lineLength := bytes.IndexByte(b[index:], '\n')
|
||||
if line == lineIndex {
|
||||
if lineLength == -1 {
|
||||
return index, len(b)
|
||||
} else {
|
||||
return index, index + lineLength
|
||||
}
|
||||
}
|
||||
if lineLength == -1 {
|
||||
break
|
||||
}
|
||||
index += lineLength + 1
|
||||
}
|
||||
|
||||
return -1, -1
|
||||
}
|
||||
Reference in New Issue
Block a user