如何解析方法声明?

huangapple go评论124阅读模式
英文:

How to parse a method declaration?

问题

我正在尝试解析一个方法声明。基本上,我需要获取接收器基本类型(type hello)和返回类型(notypeerror)的语法节点。ast包似乎很简单,但出于某种原因,我没有得到我需要的数据(即字段报告为nil)。

唯一有用的数据似乎只提供在Object -> Decl字段中,该字段的类型为interface{},所以我不认为我可以序列化它。

任何帮助将不胜感激。以下是代码:

  1. package main
  2. import (
  3. "fmt"
  4. "go/ast"
  5. "go/parser"
  6. "go/token"
  7. )
  8. func main() {
  9. // src is the input for which we want to inspect the AST.
  10. src := `
  11. package mypack
  12. // type hello is a cool type
  13. type hello string
  14. // type notype is not that cool
  15. type notype int
  16. // func printme is like nothing else.
  17. func (x *hello)printme(s string)(notype, error){
  18. return 0, nil
  19. }
  20. `
  21. // Create the AST by parsing src.
  22. fset := token.NewFileSet() // positions are relative to fset
  23. f, err := parser.ParseFile(fset, "src.go", src, 0)
  24. if err != nil {
  25. panic(err)
  26. }
  27. // Inspect the AST and find our function
  28. var mf ast.FuncDecl
  29. ast.Inspect(f, func(n ast.Node) bool {
  30. switch x := n.(type) {
  31. case *ast.FuncDecl:
  32. mf = *x
  33. }
  34. return true
  35. })
  36. if mf.Recv != nil {
  37. fmt.Printf("\n receivers:")
  38. for _, v := range mf.Recv.List {
  39. fmt.Printf(",tag %v", v.Tag)
  40. for _, xv := range v.Names {
  41. fmt.Printf("name %v, decl %v, data %v, type %v",
  42. xv.Name, xv.Obj.Decl, xv.Obj.Data, xv.Obj.Type)
  43. }
  44. }
  45. }
  46. }

Playground

英文:

I'm trying to parse a method declaration. Basically I need to get the syntax node of the receiver base type (type hello) and the return types (notype and error). The ast package seems straightforward but for some reason I don't get the data I need (i.e. the fields are reported nil).

The only useful data seems provided only in Object -> Decl field which is of type interface{} so I don't think I can serialize it.

Any help would be appreciated. Code below:

  1. package main
  2. import (
  3. "fmt"
  4. "go/ast"
  5. "go/parser"
  6. "go/token"
  7. )
  8. func main() {
  9. // src is the input for which we want to inspect the AST.
  10. src := `
  11. package mypack
  12. // type hello is a cool type
  13. type hello string
  14. // type notype is not that cool
  15. type notype int
  16. // func printme is like nothing else.
  17. func (x *hello)printme(s string)(notype, error){
  18. return 0, nil
  19. }
  20. `
  21. // Create the AST by parsing src.
  22. fset := token.NewFileSet() // positions are relative to fset
  23. f, err := parser.ParseFile(fset, "src.go", src, 0)
  24. if err != nil {
  25. panic(err)
  26. }
  27. // Inspect the AST and find our function
  28. var mf ast.FuncDecl
  29. ast.Inspect(f, func(n ast.Node) bool {
  30. switch x := n.(type) {
  31. case *ast.FuncDecl:
  32. mf = *x
  33. }
  34. return true
  35. })
  36. if mf.Recv != nil {
  37. fmt.Printf("\n receivers:")
  38. for _, v := range mf.Recv.List {
  39. fmt.Printf(",tag %v", v.Tag)
  40. for _, xv := range v.Names {
  41. fmt.Printf("name %v, decl %v, data %v, type %v",
  42. xv.Name, xv.Obj.Decl, xv.Obj.Data, xv.Obj.Type)
  43. }
  44. }
  45. }
  46. }

Playground

答案1

得分: 9

要获取类型,您需要查看Type属性,它可以是ast.StarExprast.Ident

请看这个示例:

  1. package main
  2. import (
  3. "fmt"
  4. "go/ast"
  5. "go/parser"
  6. "go/token"
  7. )
  8. func main() {
  9. // src is the input for which we want to inspect the AST.
  10. src := `
  11. package mypack
  12. // type hello is a cool type
  13. type hello string
  14. // type notype is not that cool
  15. type notype int
  16. // printme is like nothing else.
  17. func (x *hello)printme(s string)(notype, error){
  18. return 0, nil
  19. }
  20. `
  21. // Create the AST by parsing src.
  22. fset := token.NewFileSet() // positions are relative to fset
  23. f, err := parser.ParseFile(fset, "src.go", src, 0)
  24. if err != nil {
  25. panic(err)
  26. }
  27. // Inspect the AST and find our function
  28. var mf ast.FuncDecl
  29. ast.Inspect(f, func(n ast.Node) bool {
  30. switch x := n.(type) {
  31. case *ast.FuncDecl:
  32. mf = *x
  33. }
  34. return true
  35. })
  36. if mf.Recv != nil {
  37. for _, v := range mf.Recv.List {
  38. fmt.Print("recv type : ")
  39. switch xv := v.Type.(type) {
  40. case *ast.StarExpr:
  41. if si, ok := xv.X.(*ast.Ident); ok {
  42. fmt.Println(si.Name)
  43. }
  44. case *ast.Ident:
  45. fmt.Println(xv.Name)
  46. }
  47. }
  48. }
  49. }

您可以在这里查看示例。

英文:

To get the type you need to look at the Type attribute which could be an ast.StarExpr or an ast.Ident.

Here take a look at this :

  1. package main
  2. import (
  3. "fmt"
  4. "go/ast"
  5. "go/parser"
  6. "go/token"
  7. )
  8. func main() {
  9. // src is the input for which we want to inspect the AST.
  10. src := `
  11. package mypack
  12. // type hello is a cool type
  13. type hello string
  14. // type notype is not that cool
  15. type notype int
  16. // printme is like nothing else.
  17. func (x *hello)printme(s string)(notype, error){
  18. return 0, nil
  19. }
  20. `
  21. // Create the AST by parsing src.
  22. fset := token.NewFileSet() // positions are relative to fset
  23. f, err := parser.ParseFile(fset, "src.go", src, 0)
  24. if err != nil {
  25. panic(err)
  26. }
  27. // Inspect the AST and find our function
  28. var mf ast.FuncDecl
  29. ast.Inspect(f, func(n ast.Node) bool {
  30. switch x := n.(type) {
  31. case *ast.FuncDecl:
  32. mf = *x
  33. }
  34. return true
  35. })
  36. if mf.Recv != nil {
  37. for _, v := range mf.Recv.List {
  38. fmt.Print("recv type : ")
  39. switch xv := v.Type.(type) {
  40. case *ast.StarExpr:
  41. if si, ok := xv.X.(*ast.Ident); ok {
  42. fmt.Println(si.Name)
  43. }
  44. case *ast.Ident:
  45. fmt.Println(xv.Name)
  46. }
  47. }
  48. }
  49. }

huangapple
  • 本文由 发表于 2015年1月31日 08:51:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/28246970.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定