public
Last active

  • Download Gist
main.go
Go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
package gist6418462
 
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"reflect"
"runtime"
 
. "gist.github.com/5286084.git"
. "gist.github.com/5639599.git"
. "gist.github.com/6433744.git"
. "gist.github.com/6445065.git"
)
 
// Returns the source of the func f.
func GetSourceAsString(f interface{}) string {
v := reflect.ValueOf(f)
if v.IsNil() {
return "nil"
}
pc := v.Pointer()
file, line := runtime.FuncForPC(pc).FileLine(pc)
 
var startIndex, endIndex int
{
b, err := ioutil.ReadFile(file)
CheckError(err)
startIndex, endIndex = GetLineStartEndIndicies(b, line-1)
}
 
fs := token.NewFileSet()
fileAst, err := parser.ParseFile(fs, file, nil, 0*parser.ParseComments)
CheckError(err)
 
// 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 := FindFirst(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 = FindFirst(fileAst, query)
}
 
if funcAst == nil {
return fmt.Sprintf("<func src not found at %v:%v>", file, line)
}
 
return SprintAst(fs, funcAst)
}
 
var f2 = func() { panic(1337) }
 
func main() {
f := func() {
println("Hello from anon func!") // Comments are currently not preserved
}
if 5*5 > 26 {
f = f2
}
 
println(GetSourceAsString(f))
 
// Output:
// func() {
// println("Hello from anon func!")
// }
 
f2 := func(a int, b int) int {
c := a + b
return c
}
 
println(GetSourceAsString(f2))
 
// Output:
// func(a int, b int) int {
// c := a + b
// return c
// }
 
println(GetSourceAsString(GetSourceAsString))
}

A consolidated version containing all imported gist packages you're using would be nice, specially as learning material.

@divoxx, here's one someone else made. https://gist.github.com/eikenb/6487209 It's a little out of date, but it'll suffice for reading/learning purpose (i.e., if you want to actually use in your code, I recommend doing import "gist.github.com/6418462.git").

I'm working on creating a tool that will let you browse these gists in an effortless way, such that doing this manually would be unnecessary.

For what it's worth, I've implemented functionality that inlines dot imports. It mostly works, with some minor problems.

It's currently an experimental package located at:

http://godoc.org/github.com/shurcooL/go/exp/11

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.