func ParseFiles(baseDir string, filenames []string) (*App, error) {
	app := &App{
		Files: make([]*File, len(filenames)),
	}
	var (
		pkgFiles    = make(map[string][]*File)
		badDirname  string
		badPackages map[string]bool
	)
	for i, filename := range filenames {
		if strings.HasSuffix(filename, "_test.go") || strings.HasSuffix(filename, "_testmain.go") {
			continue
		}
		file, err := parseFile(baseDir, filename)
		if err != nil {
			return nil, err
		}
		app.Files[i] = file
		dirname, _ := path.Split(filename)
		if dirname == "" || dirname == "/" {
			return nil, errors.New("go files must be in a subdirectory of the app root")
		}
		dirname = dirname[:len(dirname)-1]  
		if fs := pkgFiles[dirname]; len(fs) > 0 && fs[0].PackageName != file.PackageName {
			if badDirname == "" {
				badDirname = dirname
				badPackages = map[string]bool{fs[0].PackageName: true}
			}
			if badDirname == dirname {
				badPackages[file.PackageName] = true
			}
		}
		pkgFiles[dirname] = append(pkgFiles[dirname], file)
	}
	if badDirname != "" {
		s := make([]string, 0, len(badPackages))
		for p := range badPackages {
			s = append(s, p)
		}
		sort.Strings(s)
		return nil, fmt.Errorf("multiple packages in the %s directory: %s", badDirname, strings.Join(s, ", "))
	}
	impPathPackages := make(map[string]*Package)  
	for dirname, files := range pkgFiles {
		p := &Package{
			ImportPath: dirname,
			Files:      files,
		}
		if p.ImportPath == "main" {
			return nil, errors.New("top-level main package is forbidden")
		}
		for _, f := range files {
			if f.HasInit {
				p.HasInit = true
				break
			}
		}
		app.Packages = append(app.Packages, p)
		if p.HasInit {
			app.RootPackages = append(app.RootPackages, p)
		}
		impPathPackages[p.ImportPath] = p
	}
	for _, p := range app.Packages {
		imports := make(map[string]int)  
		for _, f := range p.Files {
			for _, path := range f.ImportPaths {
				imports[path] = 1
			}
		}
		p.Dependencies = make([]*Package, 0, len(imports))
		for path := range imports {
			pkg, ok := impPathPackages[path]
			if !ok {
				continue
			}
			p.Dependencies = append(p.Dependencies, pkg)
		}
	}
	if err := topologicalSort(app.Packages); err != nil {
		return nil, err
	}
	return app, nil
}
ParseFiles parses the named files, deduces their package structure,
and returns the dependency DAG as an App.
Elements of filenames are considered relative to baseDir.
package main
import (
	"errors"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"path"
	"regexp"
	"sort"
	"strconv"
	"strings"
)
type App struct {
	Files        []*File     
	Packages     []*Package  
	RootPackages []*Package  
}
type Package struct {
	ImportPath   string      
	Files        []*File     
	Dependencies []*Package  
	HasInit      bool        
}
func (p *Package) String() string {
	return fmt.Sprintf("%+v", *p)
}
type File struct {
	Name        string    
	PackageName string    
	ImportPaths []string  
	HasInit     bool      
}
func (f *File) String() string {
	return fmt.Sprintf("%+v", *f)
}