mirror of
https://codeberg.org/scip/tablizer.git
synced 2025-12-17 20:41:03 +01:00
added
This commit is contained in:
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