Skip to content

Instantly share code, notes, and snippets.

@abiiranathan
Created March 16, 2023 08:10
Show Gist options
  • Save abiiranathan/6bafd426f748677b8dfcc79cb130f023 to your computer and use it in GitHub Desktop.
Save abiiranathan/6bafd426f748677b8dfcc79cb130f023 to your computer and use it in GitHub Desktop.
Parsing AST in go
package schemagen
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"strings"
)
// getStructsWithBuildTag retrieves all the structs in a Go source file that have a doc string containing a certain build tag.
func GetStructsWithBuildTag(filename, buildTag string) ([]string, error) {
var result []string
// Parse the file and generate an AST
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, filename, nil, parser.AllErrors|parser.ParseComments)
if err != nil {
return nil, err
}
// Iterate through all the declarations in the file
for _, decl := range node.Decls {
// Check if the declaration is a type declaration
if genDecl, ok := decl.(*ast.GenDecl); ok && genDecl.Tok == token.TYPE {
// Doc comment on type declaration
var typeMatchesTag = strings.Contains(genDecl.Doc.Text(), buildTag)
// Iterate through all the specs in the type declaration
for _, spec := range genDecl.Specs {
if typeSpec, ok := spec.(*ast.TypeSpec); ok {
// Check if the type is a struct and has a doc string containing the build tag
if stype, ok := typeSpec.Type.(*ast.StructType); ok {
// Print struct fields
for _, field := range stype.Fields.List {
if i, ok := field.Type.(*ast.Ident); ok {
fieldType := i.Name
for _, name := range field.Names {
fmt.Printf("\tField: name=%s type=%s\n", name.Name, fieldType)
}
}
}
if typeMatchesTag {
result = append(result, typeSpec.Name.Name)
continue
}
// type on struct name
if typeSpec.Doc != nil && strings.Contains(typeSpec.Doc.Text(), buildTag) {
result = append(result, typeSpec.Name.Name)
}
}
}
}
}
}
return result, nil
}
/*
print struct field
structType := typeSpec.Type.(*ast.StructType)
for _, field := range structType.Fields.List {
i := field.Type.(*ast.Ident)
fieldType := i.Name
for _, name := range field.Names {
fmt.Printf("\tField: name=%s type=%s\n", name.Name, fieldType)
}
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment