package codegen import ( "go/ast" "go/build" "go/importer" "go/parser" "go/token" "go/types" "log" "path/filepath" "strings" ) type GoParser struct { Package *Package // Package we are scanning. } // File holds a single parsed file and associated data. type File struct { pkg *Package // Package to which this file belongs. file *ast.File // Parsed AST. // These fields are reset for each type being generated. typeName string // Name of the constant type. //values []Value // Accumulator for constant values of that type. } type Package struct { dir string Name string defs map[*ast.Ident]types.Object files []*File typesPkg *types.Package } // prefixDirectory prepends the directory name on the beginning of each name in the list. func prefixDirectory(directory string, names []string) []string { if directory == "." { return names } ret := make([]string, len(names)) for i, name := range names { ret[i] = filepath.Join(directory, name) } return ret } // parsePackageDir parses the package residing in the directory. func (g *GoParser) parsePackageDir(directory string) { pkg, err := build.Default.ImportDir(directory, 0) if err != nil { log.Fatalf("cannot process directory %s: %s", directory, err) } var names []string names = append(names, pkg.GoFiles...) //names = append(names, pkg.CgoFiles...) //names = append(names, pkg.SFiles...) names = prefixDirectory(directory, names) g.parsePackage(directory, names, nil) } // parsePackage analyzes the single package constructed from the named files. // If text is non-nil, it is a string to be used instead of the content of the file, // to be used for testing. parsePackage exits if there is an error. func (g *GoParser) parsePackage(directory string, names []string, text interface{}) { var files []*File var astFiles []*ast.File g.Package = new(Package) fs := token.NewFileSet() for _, name := range names { if !strings.HasSuffix(name, ".go") { continue } parsedFile, err := parser.ParseFile(fs, name, text, 0) if err != nil { log.Fatalf("parsing package: %s: %s", name, err) } astFiles = append(astFiles, parsedFile) files = append(files, &File{ file: parsedFile, pkg: g.Package, }) } if len(astFiles) == 0 { log.Fatalf("%s: no buildable Go files", directory) } g.Package.Name = astFiles[0].Name.Name g.Package.files = files g.Package.dir = directory // Type check the package. g.Package.check(fs, astFiles) } // check type-checks the package. The package must be OK to proceed. func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) { pkg.defs = make(map[*ast.Ident]types.Object) config := types.Config{Importer: importer.Default(), FakeImportC: true} info := &types.Info{ Defs: pkg.defs, } typesPkg, err := config.Check(pkg.dir, fs, astFiles, info) if err != nil { log.Fatalf("checking package: %s", err) } pkg.typesPkg = typesPkg }