2017-10-03 4 views
1

goコード、特に関数の内容を解析したいと思います。メソッドまたは関数内のステートメントをGoで解析する方法

これまでのところ、parser.ParseFile関数を使用して関数宣言を取得するのは簡単です。

package main 

import (
    "fmt" 
    "go/parser" 
    "go/token" 
    "go/ast" 
    "log" 
) 

var code = []byte(` 
package main 

import (
    "fmt" 
) 

func GetFoo() { 
    test := foo() 
    fmt.Println(test) 
} 

func foo() int { 
    return 0 
} 
`) 

func main() { 
    fset := token.NewFileSet() 
    f, err := parser.ParseFile(fset, "", code, parser.ParseComments) 
    if err != nil { 
     log.Fatal(err) 
    } 

    for _, decl := range f.Decls { 
     switch t := decl.(type) { 
     // That's a func decl ! 
     case *ast.FuncDecl: 
      fmt.Printf("Function name: %v\n", t.Name) 
      // Now I would like to access to the test var and get its type 
      // Must be int, because foo() returns an int 
     } 
    } 

} 

今、私はtest VARにアクセスして、その型を取得したいと思いますが、私は少し失われています。私はdecl.Body.Listを見てステートメントを繰り返しますが、私はそれを得ることができますtest varはint

ありがとうございます!

https://play.golang.org/p/Y8uwM-CDWy

+3

の署名を得ることができる方法です。 [go/types](https://golang.org/pkg/go/types/)パッケージが必要になります。ここで役立つチュートリアルがあります:https://github.com/golang/example/tree/master/gotypes – JimB

答えて

1

JimBのおかげとgo/typesについての彼のヒントは、ここで私はあなただけのファイルの解析から型を得ることができない私の方法

package main 

import (
    "fmt" 
    "go/ast" 
    "go/importer" 
    "go/parser" 
    "go/token" 
    "go/types" 
    "log" 
) 

var code = []byte(` 
package main 

import (
    "fmt" 
) 

func GetFoo() { 
    test := foo() 
    fmt.Println(test) 
} 

func foo() int { 
    return 0 
} 
`) 

func main() { 
    fset := token.NewFileSet() 
    f, err := parser.ParseFile(fset, "", code, parser.ParseComments) 
    if err != nil { 
     log.Fatal(err) 
    } 

    conf := types.Config{Importer: importer.Default()} 
    pkg, err := conf.Check("cmd", fset, []*ast.File{f}, nil) 
    scope := pkg.Scope() 

    for _, decl := range f.Decls { 
     switch t := decl.(type) { 
     // That's a func decl ! 
     case *ast.FuncDecl: 
      for _, s := range t.Body.List { 
       switch as := s.(type) { 
       case *ast.AssignStmt: 
        for _, l := range as.Rhs { 
         switch rh := l.(type) { 
         case *ast.CallExpr: 
          if i, ok := rh.Fun.(*ast.Ident); ok { 
           ft := scope.Lookup(i.Name) 
           if ft != nil { 
            if ftype, ok := ft.(*types.Func); ok { 
             f := ftype.Type() 
             if sig, ok := f.(*types.Signature); ok { 
              // get the returned elements 
              r := sig.Results() 
              for i := 0; i < r.Len(); i++ { 
               v := r.At(i) 
               varTpe := v.Type() 
               fmt.Println(varTpe) 
              } 
             } 
            } 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
} 
関連する問題