dimanche 4 octobre 2020

Is possible to reflect an struct from ast in Golang?

I currently trying to implement some way to get the reflect.TypeOf() from a *ast.TypeSpec, to work with the struct without needs to import it in the code (I will explain later). For now I have this project structure:

.
├─ main.go
└─ entities
   ├─ costumer.go
   └─ person.go

Files:

// entities/costumer.go
package entities

import "time"

type Costumer struct {
    PersonId  int
    S         *int
    CreatedAt time.Time
    UpdatedAt *time.Time
    Goods     []struct {
        Name    string
        GoodsId int
    }
    Goods2
}

func (*Costumer) TableName() string {
    return "CustomName"
}

type Goods2 struct {
    Name     string
    Goods2Id int
}

// entities/person.go
package entities

type Person struct {
    Id   int
    Name string
    Age  int
}

// main.go
package main

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

// Main aa
func main() {
    // Create the AST by parsing src.
    fset := token.NewFileSet() // positions are relative to fset
    packages, err := parser.ParseDir(fset, "./entities", nil, 0)

    if err != nil {
        panic(err)
    }

    for _, pack := range packages {

        for _, file := range pack.Files {
            // Inspect the AST and print all identifiers and literals.
            ast.Inspect(file, func(n ast.Node) bool {
                switch x := n.(type) {
                case *ast.TypeSpec: // Gets Type assertions
                    fmt.Println(x.Name.Name)

                    v := x.Type.(*ast.StructType)
                    for _, field := range v.Fields.List {

                        for _, name := range field.Names {

                            // get field.Type as string
                            var typeNameBuf bytes.Buffer
                            err := printer.Fprint(&typeNameBuf, fset, field.Type)
                            if err != nil {
                                log.Fatalf("failed printing %s", err)
                            }
                            fmt.Printf("field %+v has type %+v\n", name.Name, typeNameBuf.String())
                        }

                    }
                    fmt.Println()

                }

                return true
            })
        }
    }
}

And I need some way to get Costumer, Goods2 and Person structs to use in the code. For now I want specifically call the Costumer.TableName method and receive the result of it.

I can't import the package because later it will be a CLI and will recive just the folder to parse/inspect (parser.ParseDir(fset, "<folder goes here>", nil, 0))

So any ideas, suggestions or tips?





Aucun commentaire:

Enregistrer un commentaire