func (g *Generator) GenerateFromFunction(
	f *ast.FuncDecl, entities []string, cfg *ReifyConfig,
	updateTypes, updateName bool,
) error {
	for _, reified := range cfg.Permutations() {
		if updateTypes {
			ids := g.getIdentifiers(f)
			for i := range ids {
				id := ids[i]
				if contains(entities, id.Name) {
					originalName := id.Name
					id.Name = originalName + reified.NameExtension()
					g.todo.Append(func() {
						id.Name = originalName
					})
				}
			}
		}
		if updateName {
			originalName := f.Name.Name
			f.Name.Name = originalName + reified.NameExtension()
			g.todo.Append(func() {
				f.Name.Name = originalName
			})
			names := map[string]string{}
			for _, e := range entities {
				names[e] = e + reified.NameExtension()
			}
			g.replaceComment(f.Doc, originalName, f.Name.Name)
			g.replaceReferences(f, names)
		}
		var nodestack []ast.Node
		ast.Inspect(f, func(n ast.Node) bool {
			if n == nil {
				nodestack = nodestack[:len(nodestack)-1]
				return false
			}
			if expr, ok := n.(ast.Expr); ok {
				ne := g.transformExpression(reified, expr)
				if ne != nil {
					parent := nodestack[len(nodestack)-1]
					g.todo.Append(func() {
						g.replaceExpr(parent, ne, expr)
					})
					g.replaceExpr(parent, expr, ne)
				}
			}
			nodestack = append(nodestack, n)
			return true
		})
		printer.Fprint(&g.code, g.fset, []ast.Decl{f})
		g.code.WriteString("\n\n")
		g.todo.Run()
	}
	return nil
}
GenerateFromFunction generates definitions from the given function
package main
import (
	"bytes"
	"go/ast"
	"go/printer"
	"go/token"
	"io"
	"path"
	"reflect"
	"strings"
	"github.com/badgerodon/goreify/generics"
)
type Generator struct {
	pkgname string
	imports map[string]string
	code    bytes.Buffer
	fset    *token.FileSet
	todo FunctionStack
}
func NewGenerator(pkgname string, fset *token.FileSet) *Generator {
	return &Generator{
		pkgname: pkgname,
		imports: map[string]string{},
		fset:    fset,
	}
}
func (g *Generator) GenerateFromFile(file *ast.File, entities []string, cfg *ReifyConfig) error {
	for _, i := range file.Imports {
		value := i.Path.Value
		if len(value) > 0 && value[0] == '"' {
			value = value[1:]
		}
		if len(value) > 0 && value[len(value)-1] == '"' {
			value = value[:len(value)-1]
		}
		name := path.Base(value)
		if i.Name != nil {
			name = i.Name.Name
		}
		g.imports[name] = value
	}
	for _, decl := range file.Decls {
		switch t := decl.(type) {
		case *ast.FuncDecl:
			isGenericFunction := false
			isMethod := false
			isGlobalFunction := false
			if contains(entities, t.Name.Name) {
				isGenericFunction = true
			} else {
				if t.Recv != nil && len(t.Recv.List) > 0 {
					for _, ident := range g.getIdentifiers(t.Recv) {
						if contains(entities, ident.Name) {
							isMethod = true
							break
						}
					}
				}
				if t.Type.Results != nil && len(t.Type.Results.List) > 0 {
					for _, ident := range g.getIdentifiers(t.Type.Results) {
						if contains(entities, ident.Name) {
							isGlobalFunction = true
							break
						}
					}
				}
			}
			if isGenericFunction || isMethod || isGlobalFunction {
				err := g.GenerateFromFunction(t, entities, cfg,
					isMethod || isGlobalFunction,
					(isGenericFunction || isGlobalFunction) && !isMethod)
				if err != nil {
					return err
				}
			}
		case *ast.GenDecl:
			if t.Tok == token.TYPE {
				for _, s := range t.Specs {
					spec := s.(*ast.TypeSpec)
					if !contains(entities, spec.Name.Name) {
						continue
					}
					err := g.GenerateFromType(file, t, entities, spec, cfg)
					if err != nil {
						return err
					}
				}
			}
		default:
		}
	}
	return nil
}