You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
4.5 KiB
194 lines
4.5 KiB
5 years ago
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"go/ast"
|
||
|
"go/parser"
|
||
|
"go/token"
|
||
|
"io/ioutil"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
type param struct{ K, V, P string }
|
||
|
|
||
|
type parse struct {
|
||
|
Path string
|
||
|
Package string
|
||
|
// Imports []string
|
||
|
Imports map[string]*param
|
||
|
// Structs []*param
|
||
|
// Interfaces []string
|
||
|
Funcs []*struct {
|
||
|
Name string
|
||
|
Method, Params, Result []*param
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func parseArgs(args []string, res *[]string, index int) (err error) {
|
||
|
if len(args) <= index {
|
||
|
return
|
||
|
}
|
||
|
if strings.HasPrefix(args[index], "-") {
|
||
|
index += 2
|
||
|
parseArgs(args, res, index)
|
||
|
return
|
||
|
}
|
||
|
var f os.FileInfo
|
||
|
if f, err = os.Stat(args[index]); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if f.IsDir() {
|
||
|
if !strings.HasSuffix(args[index], "/") {
|
||
|
args[index] += "/"
|
||
|
}
|
||
|
var fs []os.FileInfo
|
||
|
if fs, err = ioutil.ReadDir(args[index]); err != nil {
|
||
|
return
|
||
|
}
|
||
|
for _, f = range fs {
|
||
|
path, _ := filepath.Abs(args[index] + f.Name())
|
||
|
args = append(args, path)
|
||
|
}
|
||
|
} else {
|
||
|
if strings.HasSuffix(args[index], ".go") &&
|
||
|
!strings.HasSuffix(args[index], "_test.go") {
|
||
|
*res = append(*res, args[index])
|
||
|
}
|
||
|
}
|
||
|
index++
|
||
|
return parseArgs(args, res, index)
|
||
|
}
|
||
|
|
||
|
func parseFile(files ...string) (parses []*parse, err error) {
|
||
|
for _, file := range files {
|
||
|
var (
|
||
|
astFile *ast.File
|
||
|
fSet = token.NewFileSet()
|
||
|
parse = &parse{
|
||
|
Imports: make(map[string]*param),
|
||
|
}
|
||
|
)
|
||
|
if astFile, err = parser.ParseFile(fSet, file, nil, 0); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if astFile.Name != nil {
|
||
|
parse.Path = file
|
||
|
parse.Package = astFile.Name.Name
|
||
|
}
|
||
|
for _, decl := range astFile.Decls {
|
||
|
switch decl.(type) {
|
||
|
case *ast.GenDecl:
|
||
|
if specs := decl.(*ast.GenDecl).Specs; len(specs) > 0 {
|
||
|
parse.Imports = parseImports(specs)
|
||
|
}
|
||
|
case *ast.FuncDecl:
|
||
|
var (
|
||
|
dec = decl.(*ast.FuncDecl)
|
||
|
parseFunc = &struct {
|
||
|
Name string
|
||
|
Method, Params, Result []*param
|
||
|
}{Name: dec.Name.Name}
|
||
|
)
|
||
|
if dec.Recv != nil {
|
||
|
parseFunc.Method = parserParams(dec.Recv.List)
|
||
|
}
|
||
|
if dec.Type.Params != nil {
|
||
|
parseFunc.Params = parserParams(dec.Type.Params.List)
|
||
|
}
|
||
|
if dec.Type.Results != nil {
|
||
|
parseFunc.Result = parserParams(dec.Type.Results.List)
|
||
|
}
|
||
|
parse.Funcs = append(parse.Funcs, parseFunc)
|
||
|
}
|
||
|
}
|
||
|
parses = append(parses, parse)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func parserParams(fields []*ast.Field) (params []*param) {
|
||
|
for _, field := range fields {
|
||
|
p := ¶m{}
|
||
|
p.V = parseType(field.Type)
|
||
|
if field.Names == nil {
|
||
|
params = append(params, p)
|
||
|
}
|
||
|
for _, name := range field.Names {
|
||
|
sp := ¶m{}
|
||
|
sp.K = name.Name
|
||
|
sp.V = p.V
|
||
|
sp.P = p.P
|
||
|
params = append(params, sp)
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func parseType(expr ast.Expr) string {
|
||
|
switch expr.(type) {
|
||
|
case *ast.Ident:
|
||
|
return expr.(*ast.Ident).Name
|
||
|
case *ast.StarExpr:
|
||
|
return "*" + parseType(expr.(*ast.StarExpr).X)
|
||
|
case *ast.ArrayType:
|
||
|
return "[" + parseType(expr.(*ast.ArrayType).Len) + "]" + parseType(expr.(*ast.ArrayType).Elt)
|
||
|
case *ast.SelectorExpr:
|
||
|
return parseType(expr.(*ast.SelectorExpr).X) + "." + expr.(*ast.SelectorExpr).Sel.Name
|
||
|
case *ast.MapType:
|
||
|
return "map[" + parseType(expr.(*ast.MapType).Key) + "]" + parseType(expr.(*ast.MapType).Value)
|
||
|
case *ast.StructType:
|
||
|
return "struct{}"
|
||
|
case *ast.InterfaceType:
|
||
|
return "interface{}"
|
||
|
case *ast.FuncType:
|
||
|
var (
|
||
|
pTemp string
|
||
|
rTemp string
|
||
|
)
|
||
|
pTemp = parseFuncType(pTemp, expr.(*ast.FuncType).Params)
|
||
|
if expr.(*ast.FuncType).Results != nil {
|
||
|
rTemp = parseFuncType(rTemp, expr.(*ast.FuncType).Results)
|
||
|
return fmt.Sprintf("func(%s) (%s)", pTemp, rTemp)
|
||
|
}
|
||
|
return fmt.Sprintf("func(%s)", pTemp)
|
||
|
case *ast.ChanType:
|
||
|
return fmt.Sprintf("make(chan %s)", parseType(expr.(*ast.ChanType).Value))
|
||
|
case *ast.Ellipsis:
|
||
|
return parseType(expr.(*ast.Ellipsis).Elt)
|
||
|
}
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
func parseFuncType(temp string, data *ast.FieldList) string {
|
||
|
var params = parserParams(data.List)
|
||
|
for i, param := range params {
|
||
|
if i == 0 {
|
||
|
temp = param.K + " " + param.V
|
||
|
continue
|
||
|
}
|
||
|
t := param.K + " " + param.V
|
||
|
temp = fmt.Sprintf("%s, %s", temp, t)
|
||
|
}
|
||
|
return temp
|
||
|
}
|
||
|
|
||
|
func parseImports(specs []ast.Spec) (params map[string]*param) {
|
||
|
params = make(map[string]*param)
|
||
|
for _, spec := range specs {
|
||
|
switch spec.(type) {
|
||
|
case *ast.ImportSpec:
|
||
|
p := ¶m{V: strings.Replace(spec.(*ast.ImportSpec).Path.Value, "\"", "", -1)}
|
||
|
if spec.(*ast.ImportSpec).Name != nil {
|
||
|
p.K = spec.(*ast.ImportSpec).Name.Name
|
||
|
params[p.K] = p
|
||
|
} else {
|
||
|
vs := strings.Split(p.V, "/")
|
||
|
params[vs[len(vs)-1]] = p
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|